smp.tex
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:17k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. From: michael@Physik.Uni-Dortmund.DE (Michael Dirkmann)
  2. thanks for your information. Attached is the tex-code of your
  3. SMP-documentation :
  4. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  5. documentclass[]{article}
  6. parindent0.0cm
  7. parskip0.2cm
  8. begin{document}
  9. begin{center}
  10. LARGE bf
  11. An Implementation Of Multiprocessor Linux
  12. normalsize
  13. end{center}
  14. { it
  15. This document describes the implementation of a simple SMP 
  16. Linux kernel extension and how to use this to develop SMP Linux kernels for 
  17. architectures other than the Intel MP v1.1 architecture for Pentium and 486 
  18. processors.}
  19. hfill Alan Cox, 1995
  20. The author wishes to thank Caldera Inc. ( http://www.caldera.com )
  21. whose donation of an ASUS dual Pentium board made this project possible, 
  22. and Thomas Radke, whose initial work on multiprocessor Linux formed 
  23. the backbone of this project.
  24. section{Background: The Intel MP specification.}
  25. Most IBM PC style multiprocessor motherboards combine Intel 486 or Pentium 
  26. processors and glue chipsets with a hardware/software specification. The 
  27. specification places much of the onus for hard work on the chipset and 
  28. hardware rather than the operating system.
  29. The Intel Pentium processors have a wide variety of inbuilt facilities for 
  30. supporting multiprocessing, including hardware cache coherency, built in 
  31. interprocessor interrupt handling and a set of atomic test and set, 
  32. exchange and similar operations. The cache coherency in particular makes the 
  33. operating system's job far easier.
  34. The specification defines a detailed configuration structure in ROM that 
  35. the boot up processor can read to find the full configuration of the 
  36. processors and buses. It also defines a procedure for starting up the 
  37. other processors.
  38. section{Mutual Exclusion Within A Single Processor Linux Kernel}
  39. For any kernel to function in a sane manner it has to provide internal 
  40. locking and protection of its own tables to prevent two processes updating 
  41. them at once and for example allocating the same memory block. There are 
  42. two strategies for this within current Unix and Unixlike kernels. 
  43. Traditional Unix systems from the earliest of days use a scheme of 'Coarse 
  44. Grained Locking' where the entire kernel is protected by a small number of 
  45. locks only. Some modern systems use fine grained locking. Because fine 
  46. grained locking has more overhead it is normally used only on 
  47. multiprocessor kernels and real time kernels. In a real time kernel the 
  48. fine grained locking reduces the amount of time locks are held and reduces 
  49. the critical (to real time programming at least) latency times.
  50. Within the Linux kernel certain guarantees are made. No process running in 
  51. kernel mode will be pre-empted by another kernel mode process unless it 
  52. voluntarily sleeps.  This ensures that blocks of kernel code are 
  53. effectively atomic with respect to other processes and greatly simplifies 
  54. many operations. Secondly interrupts may pre-empt a kernel running process, 
  55. but will always return to that process. A process in kernel mode may 
  56. disable interrupts on the processor and guarantee such an interruption will 
  57. not occur. The final guarantee is that an interrupt will not be pre-empted 
  58. by a kernel task. That is interrupts will run to completion or be 
  59. pre-empted by other interrupts only.
  60. The SMP kernel chooses to continue these basic guarantees in order to make 
  61. initial implementation and deployment easier.  A single lock is maintained 
  62. across all processors. This lock is required to access the kernel space. 
  63. Any processor may hold it and once it is held may also re-enter the kernel 
  64. for interrupts and other services whenever it likes until the lock is 
  65. relinquished. This lock ensures that a kernel mode process will not be 
  66. pre-empted and ensures that blocking interrupts in kernel mode behaves 
  67. correctly. This is guaranteed because only the processor holding the lock 
  68. can be in kernel mode, only kernel mode processes can disable interrupts 
  69. and only the processor holding the lock may handle an interrupt.
  70. Such a choice is however poor for performance. In the longer term it is 
  71. necessary to move to finer grained parallelism in order to get the best 
  72. system performance. This can be done hierarchically by gradually refining 
  73. the locks to cover smaller areas. With the current kernel highly CPU bound 
  74. process sets perform well but I/O bound task sets can easily degenerate to 
  75. near single processor performance levels. This refinement will be needed to 
  76. get the best from Linux/SMP.
  77. subsection{Changes To The Portable Kernel Components}
  78. The kernel changes are split into generic SMP support changes and 
  79. architecture specific changes necessary to accommodate each different 
  80. processor type Linux is ported to.
  81. subsubsection{Initialisation}
  82. The first problem with a multiprocessor kernel is starting the other 
  83. processors up. Linux/SMP defines that a single processor enters the normal 
  84. kernel entry point start_kernel(). Other processors are assumed not to be 
  85. started or to have been captured elsewhere. The first processor begins the 
  86. normal Linux initialisation sequences and sets up paging, interrupts and 
  87. trap handlers. After it has obtained the processor information about the 
  88. boot CPU, the architecture specific function 
  89. {tt bf{void smp_store_cpu_info(int processor_id) }}
  90. is called to store any information about the processor into a per processor 
  91. array. This includes things like the bogomips speed ratings.
  92. Having completed the kernel initialisation the architecture specific 
  93. function
  94. {tt bf void smp_boot_cpus(void) }
  95. is called and is expected to start up each other processor and cause it to 
  96. enter start_kernel() with its paging registers and other control 
  97. information correctly loaded. Each other processor skips the setup except 
  98. for calling the trap and irq initialisation functions that are needed on 
  99. some processors to set each CPU up correctly.  These functions will 
  100. probably need to be modified in existing kernels to cope with this.
  101. Each additional CPU then calls the architecture specific function
  102. {tt bf void smp_callin(void)}
  103. which does any final setup and then spins the processor while the boot 
  104. up processor forks off enough idle threads for each processor. This is 
  105. necessary because the scheduler assumes there is always something to run. 
  106. Having generated these threads and forked init the architecture specific 
  107. {tt bf void smp_commence(void)}
  108. function is invoked. This does any final setup and indicates to the system 
  109. that multiprocessor mode is now active. All the processors spinning in the 
  110. smp_callin() function are now released to run the idle processes, which 
  111. they will run when they have no real work to process.
  112. subsubsection{Scheduling}
  113. The kernel scheduler implements a simple but very effective task 
  114. scheduler. The basic structure of this scheduler is unchanged in the 
  115. multiprocessor kernel. A processor field is added to each task, and this 
  116. maintains the number of the processor executing a given task, or a magic 
  117. constant (NO_PROC_ID)  indicating the job is not allocated to a processor. 
  118.  
  119. Each processor executes the scheduler itself and will select the next task 
  120. to run from all runnable processes not allocated to a different processor. 
  121. The algorithm used by the selection is otherwise unchanged. This is 
  122. actually inadequate for the final system because there are advantages to 
  123. keeping a process on the same CPU, especially on processor boards with per 
  124. processor second level caches.
  125. Throughout the kernel the variable 'current' is used as a global for the 
  126. current process. In Linux/SMP this becomes a macro which expands to 
  127. current_set[smp_processor_id()]. This enables almost the entire kernel to 
  128. be unaware of the array of running processors, but still allows the SMP 
  129. aware kernel modules to see all of the running processes.
  130. The fork system call is modified to generate multiple processes with a 
  131. process id of zero until the SMP kernel starts up properly. This is 
  132. necessary because process number 1 must be init, and it is desirable that 
  133. all the system threads are process 0. 
  134. The final area within the scheduling of processes that does cause problems 
  135. is the fact the uniprocessor kernel hard codes tests for the idle threads 
  136. as task[0] and the init process as task[1]. Because there are multiple idle 
  137. threads it is necessary to replace these with tests that the process id is 
  138. 0 and a search for process ID 1, respectively.
  139. subsubsection{Memory Management}
  140. The memory management core of the existing Linux system functions 
  141. adequately within the multiprocessor framework providing the locking is 
  142. used. Certain processor specific areas do need changing, in particular 
  143. invalidate() must invalidate the TLBs of all processors before it returns.
  144. subsubsection{Miscellaneous Functions}
  145. The portable SMP code rests on a small set of functions and variables 
  146. that are provided by the processor specification functionality. These are
  147. {tt bf int smp_processor_id(void) }
  148. which returns the identity of the processor the call is executed upon. This 
  149. call is assumed to be valid at all times. This may mean additional tests 
  150. are needed during initialisation.
  151. {tt bf int smp_num_cpus;}
  152. This is the number of processors in the system. 
  153. {tt bf void smp_message_pass(int target, int msg, unsigned long data,
  154. int wait)}
  155. This function passes messages between processors. At the moment it is not 
  156. sufficiently defined to sensibly document and needs cleaning up and further 
  157. work. Refer to the processor specific code documentation for more details.
  158. subsection{Architecture Specific Code For the Intel MP Port}
  159. The architecture specific code for the Intel port splits fairly cleanly 
  160. into four sections. Firstly the initialisation code used to boot the 
  161. system, secondly the message handling and support code, thirdly the 
  162. interrupt and kernel syscall entry function handling and finally the 
  163. extensions to standard kernel facilities to cope with multiple processors.
  164. subsubsection{Initialisation}
  165. The Intel MP architecture captures all the processors except for a single 
  166. processor known as the 'boot processor' in the BIOS at boot time. Thus a 
  167. single processor enters the kernel bootup code. The first processor 
  168. executes the bootstrap code, loads and uncompresses the kernel. Having 
  169. unpacked the kernel it sets up the paging and control registers then enters 
  170. the C kernel startup.
  171. The assembler startup code for the kernel is modified so that it can be 
  172. used by the other processors to do the processor identification and various 
  173. other low level configurations but does not execute those parts of the 
  174. startup code that would damage the running system (such as clearing the BSS 
  175. segment). 
  176. In the initialisation done by the first processor the arch/i386/mm/init 
  177. code is modified to scan the low page, top page and BIOS for intel MP 
  178. signature blocks. This is necessary because the MP signature blocks must 
  179. be read and processed before the kernel is allowed to allocate and destroy 
  180. the page at the top of low memory. Having established the number of 
  181. processors it reserves a set of pages to provide a stack come boot up area 
  182. for each processor in the system. These must be allocated at startup to 
  183. ensure they fall below the 1Mb boundary.
  184. Further processors are started up in smp_boot_cpus() by programming the 
  185. APIC controller registers and sending an inter-processor interrupt (IPI) to 
  186. the processor. This message causes the target processor to begin executing 
  187. code at the start of any page of memory within the lowest 1Mb, in 16bit 
  188. real mode. The kernel uses the single page it allocated for each processor 
  189. to use as stack. Before booting a given CPU the relocatable code from 
  190. trampoline.S and trampoline32.S is copied to the bottom of its stack page 
  191. and used as the target for the startup. 
  192. The trampoline code calculates the desired stack base from the code 
  193. segment (since the code segment on startup is the bottom of the stack), 
  194.  enters 32bit mode and jumps to the kernel entry assembler. This as 
  195. described above is modified to only execute the parts necessary for each 
  196. processor, and then to enter start_kernel(). On entering the kernel the 
  197. processor initialises its trap and interrupt handlers before entering 
  198. smp_callin(), where it reports its status and sets a flag that causes the 
  199. boot processor to continue and look for further processors. The processor 
  200. then spins until smp_commence() is invoked.
  201. Having started each processor up the smp_commence( ) function flips a 
  202. flag. Each processor spinning in smp_callin() then loads the task register 
  203. with the task state segment (TSS) of its idle thread as is needed for task 
  204. switching.
  205. subsubsection{Message Handling and Support Code}
  206. The architecture specific code implements the smp_processor_id() function 
  207. by querying the APIC logical identity register. Because the APIC isn't 
  208. mapped into the kernel address space at boot, the initial value returned is 
  209. rigged by setting the APIC base pointer to point at a suitable constant. 
  210. Once the system starts doing the SMP setup (in smp_boot_cpus()), the APIC 
  211. is mapped with a vremap() call and the apic pointer is adjusted 
  212. appropriately. From then on the real APIC logical identity register is 
  213. read.
  214. Message passing is accomplished using a pair of IPIs on interrupt 13 
  215. (unused by the 80486 FPUs in SMP mode) and interrupt 16. Two are used in 
  216. order to separate messages that cannot be processed until the receiver 
  217. obtains the kernel spinlock from messages that can be processed 
  218. immediately. In effect IRQ 13 is a fast IRQ handler that does not obtain 
  219. the locks, and cannot cause a reschedule, while IRQ 16 is a slow IRQ that 
  220. must acquire the kernel spinlocks and can cause a reschedule. This 
  221. interrupt is used for passing on slave timer messages from the processor 
  222. that receives the timer interrupt to the rest of the processors, so that 
  223. they can reschedule running tasks.
  224. subsubsection{Entry And Exit Code}
  225. A single spinlock protects the entire kernel. The interrupt handlers, the 
  226. syscall entry code and the exception handlers all acquire the lock before 
  227. entering the kernel proper. When the processor is trying to acquire the 
  228. spinlock it spins continually on the lock with interrupts disabled. This 
  229. causes a specific deadlock problem. The lock owner may need to send an 
  230. invalidate request to the rest of the processors and wait for these to 
  231. complete before continuing. A processor spinning on the lock would not be 
  232. able to do this. Thus the loop of the spinlock tests and handles invalidate 
  233. requests. If the invalidate bit for the spinning CPU is set the processor 
  234. invalidates its TLB and atomically clears the bit. When the spinlock is 
  235. obtained that processor will take an IPI and in the IPI test the bit and 
  236. skip the invalidate as the bit is clear.
  237. One complexity of the spinlock is that a process running in kernel mode 
  238. can sleep voluntarily and be pre-empted. A switch from such a process to a 
  239. process executing in user space may reduce the lock count. To track this 
  240. the kernel uses a syscall_count and a per process lock_depth parameter to 
  241. track the kernel lock state. The switch_to() function is modified in SMP 
  242. mode to adjust the lock appropriately.
  243. The final problem is the idle thread. In the single processor kernel the 
  244. idle thread executes 'hlt' instructions. This saves power and reduces the 
  245. running temperature of the processors when they are idle. However it means 
  246. the process spends all its time in kernel mode and would thus hold the 
  247. kernel spinlock. The SMP idle thread continually reschedules a new task and 
  248. returns to user mode. This is far from ideal and will be modified to use 
  249. 'hlt' instructions and release the spinlock soon. Using 'hlt' is even more 
  250. beneficial on a multiprocessor system as it almost completely takes an idle 
  251. processor off the bus.
  252. Interrupts are distributed by an i82489 APIC. This chip is set up to work 
  253. as an emulation of the traditional PC interrupt controllers when the 
  254. machine boots (so that an Intel MP machine boots one CPU and PC 
  255. compatible). The kernel has all the relevant locks but does not yet 
  256. reprogram the 82489 to deliver interrupts to arbitrary processors as it 
  257. should. This requires further modification of the standard Linux interrupt 
  258. handling code, and is particularly messy as the interrupt handler behaviour 
  259. has to change as soon as the 82489 is switched into SMP mode.
  260. subsubsection{Extensions To Standard Facilities}
  261. The kernel maintains a set of per processor control information such as 
  262. the speed of the processor for delay loops. These functions on the SMP 
  263. kernel look the values up in a per processor array that is set up from the 
  264. data generated at boot up by the smp_store_cpu_info() function. This 
  265. includes other facts such as whether there is an FPU on the processor. The 
  266. current kernel does not handle floating point correctly, this requires some 
  267. changes to the techniques the single CPU kernel uses to minimise floating 
  268. point processor reloads.
  269. The highly useful atomic bit operations are prefixed with the 'lock' 
  270. prefix in the SMP kernel to maintain their atomic properties when used 
  271. outside of (and by) the spinlock and message code. Amongst other things 
  272. this is needed for the invalidate handler, as all  CPU's will invalidate at 
  273. the same time without any locks.
  274. Interrupt 13 floating point error reporting is removed. This facility is 
  275. not usable on a multiprocessor board, nor relevant to the Intel MP 
  276. architecture which does not cover the 80386/80387 processor pair. 
  277. The /proc filesystem support is changed so that the /proc/cpuinfo file 
  278. contains a column for each processor present. This information is extracted 
  279. from the data saved by smp_store_cpu_info().
  280. end{document}