|
| CONTENTS |
|
| LIST OF FIGURES | xvi |
| LIST OF TABLES | xxii |
| FOREWORD | xxv |
| PREFACE | xxix |
| 1 | INTRODUCTION | 1 |
| 1.1 | Microprocessors: from CISC to EPIC | 1 |
| 1.1.1 | Summary of microprocessor taxonomy | 4 |
| 1.1.2 | The IA-64 architecture and Itanium | 4 |
| 1.2 | A Brief History of Linux | 5 |
| 1.2.1 | The early days | 6 |
| 1.2.2 | Branching out: Linux goes multiplatform | 7 |
| 1.2.3 | IA-64 Linux | 8 |
| 1.2.4 | Summary of Linux history | 8 |
| 1.3 | Overview of the Linux Kernel | 9 |
| 1.3.1 | Key concepts | 10 |
| 1.3.2 | Hardware model | 19 |
| 1.3.3 | Kernel components | 20 |
| 1.3.4 | The kernel source code | 25 |
| 1.4 | Summary | 27 |
| 2 | IA-64 ARCHITECTURE | 29 |
| 2.1 | User-Level Instruction Set Architecture | 31 |
| 2.1.1 | Instruction format | 31 |
| 2.1.2 | Instruction sequencing | 32 |
| 2.1.3 | Register files | 34 |
| 2.1.4 | Instruction set overview | 40 |
| 2.1.5 | Integer and SIMD instructions | 41 |
| 2.1.6 | Memory and semaphore instructions | 42 |
| 2.1.7 | Branch instructions | 45 |
| 2.1.8 | Register-stack-related instructions | 47 |
| 2.1.9 | Control instructions | 50 |
| 2.1.10 | Floating-point instructions | 51 |
| 2.1.11 | Modulo-scheduled loops | 51 |
| 2.2 | Runtime and Software Conventions | 55 |
| 2.2.1 | Data model | 55 |
| 2.2.2 | Register usage | 56 |
| 2.2.3 | Procedure linkage | 62 |
| 2.2.4 | Memory stack | 60 |
| 2.2.5 | Register stack | 60 |
| 2.2.6 | The global pointer | 60 |
| 2.2.7 | Programming in IA-64 assembly language | 62 |
| 2.3 | System Instruction Set Architecture | 66 |
| 2.3.1 | System register files | 66 |
| 2.3.2 | Privileged instructions | 71 |
| 2.3.3 | Interruptions | 72 |
| 2.4 | The Register Stack Engine (RSE) | 75 |
| 2.4.1 | The register stack configuration register (rsc) | 77 |
| 2.4.2 | Dealing with NaT bits | 78 |
| 2.4.3 | RSE arithmetic | 80 |
| 2.4.4 | Convenience routines for RSE arithmetic | 81 |
| 2.4.5 | Instructions that affect the RSE | 82 |
| 2.5 | Summary | 84 |
| 3 | PROCESSES, TASKS, AND THREADS | 85 |
| 3.1 | Introduction to Linux Tasks | 87 |
| 3.1.1 | Task creation | 89 |
| 3.1.2 | Historical perspective | 92 |
| 3.2 | The Thread Interface | 93 |
| 3.2.1 | The pt-regs structure | 94 |
| 3.2.2 | The switch-stack structure | 95 |
| 3.2.3 | The thread structure | 98 |
| 3.2.4 | IA-64 register stack | 101 |
| 3.2.5 | Summary of IA-64 thread state | 102 |
| 3.2.6 | Running threads | 103 |
| 3.2.7 | Creating threads | 108 |
| 3.2.8 | Terminating threads | 114 |
| 3.2.9 | Moving threads across the address-space boundary | 115 |
| 3.3 | Thread Synchronization | 117 |
| 3.3.1 | Concurrency model | 118 |
| 3.3.2 | Atomic operations | 119 |
| 3.3.3 | Semaphores | 124 |
| 3.3.4 | Interrupt masking | 125 |
| 3.3.5 | Spinlocks | 127 |
| 3.4 | Summary | 128 |
| 4 | VIRTUAL MEMORY | 131 |
| 4.1 | Introduction to the Virtual Memory System | 132 |
| 4.1.1 | Virtual-to-physical address translation | 133 |
| 4.1.2 | Demand paging | 134 |
| 4.1.3 | Paging and swapping | 134 |
| 4.1.4 | Protection | 136 |
| 4.2 | Address Space of a Linux Process | 138 |
| 4.2.1 | User address space | 139 |
| 4.2.2 | Page-table-mapped kernel segment | 144 |
| 4.2.3 | Identity-mapped kernel segment | 144 |
| 4.2.4 | Structure of IA-64 address space | 148 |
| 4.3 | Page Tables | 152 |
| 4.3.1 | Collapsing page-table levels | 155 |
| 4.3.2 | Virtually-mapped linear page tables | 155 |
| 4.3.3 | Structure of Linux/ia64 page tables | 158 |
| 4.3.4 | Page table entries (PTEs) | 161 |
| 4.3.5 | Page table accesses | 168 |
| 4.3.6 | Page table directory creation | 173 |
| 4.4 | Translation Lookaside Buffer (TLB) | 174 |
| 4.4.1 | The IA-64 TLB architecture | 176 |
| 4.4.2 | Maintenance of TLB coherency | 182 |
| 4.4.3 | Lazy TLB flushing | 185 |
| 4.5 | Page Fault Handling | 187 |
| 4.5.1 | Example: How copy-on-write really works | 188 |
| 4.5.2 | The Linux page fault handler | 191 |
| 4.5.3 | IA-64 implementation | 192 |
| 4.6 | Memory Coherency | 200 |
| 4.6.1 | Maintenance of coherency in the Linux kernel | 201 |
| 4.6.2 | IA-64 implementation | 203 |
| 4.7 | Switching Address Spaces | 205 |
| 4.7.1 | Address-space switch interface | 205 |
| 4.7.2 | IA-64 implementation | 206 |
| 4.8 | Discussion and Summary | 206 |
| 5 | KERNEL ENTRY AND EXIT | 209 |
| 5.1 | Interruptions | 210 |
| 5.1.1 | Kernel entry path | 211 |
| 5.1.2 | Kernel exit path | 211 |
| 5.1.3 | Discussion | 213 |
| 5.1.4 | IA-64 implementation | 214 |
| 5.1.5 | Switching the IA-64 register stack | 217 |
| 5.2 | System Calls | 225 |
| 5.2.1 | Signaling errors | 226 |
| 5.2.2 | Restarting system call execution | 227 |
| 5.2.3 | Invoking system calls from the kernel | 230 |
| 5.2.4 | IA-64 implementation | 230 |
| 5.3 | Signals | 238 |
| 5.3.1 | Signal-related system calls | 239 |
| 5.3.2 | Signal delivery | 243 |
| 5.3.3 | IA-64 implementation | 246 |
| 5.4 | Kernel Access to User Memory | 251 |
| 5.4.1 | Example: How gettimeofday() returns the timeval structure | 254 |
| 5.4.2 | Disabling validity checking | 256 |
| 5.4.3 | IA-64 implementation | 257 |
| 5.5 | Summary | 261 |
| 6 | STACK UNWINDING | 263 |
| 6.1 | IA-64 ELF Unwind Sections | 265 |
| 6.2 | The Kernel Unwind Interface | 267 |
| 6.2.1 | Managing unwind tables | 267 |
| 6.2.2 | Navigating through the call chain | 267 |
| 6.2.3 | Accessing the CPU state of the current frame | 269 |
| 6.2.4 | Using the unwind interface | 273 |
| 6.3 | Embedding Unwind Information in Assembly Code | 276 |
| 6.3.1 | Region directives | 278 |
| 6.3.2 | Prologue directives | 280 |
| 6.3.3 | Body directives | 282 |
| 6.3.4 | General directives | 282 |
| 6.3.5 | Examples | 283 |
| 6.4 | Implementation Aspects | 285 |
| 6.4.1 | The frame info structure | 285 |
| 6.4.2 | Unwind descriptor processing | 287 |
| 6.4.3 | Unwind scripts | 289 |
| 6.4.4 | Lazy initialization and script hinting | 292 |
| 6.4.5 | Putting it all together | 293 |
| 6.5 | Summary | 294 |
| 7 | DEVICE I/O | 295 |
| 7.1 | Introduction | 295 |
| 7.1.1 | Organization of modern machines | 297 |
| 7.1.2 | Software support for I/O on modern machines | 298 |
| 7.2 | Programmed I/O | 299 |
| 7.2.1 | Memory-mapped I/O | 299 |
| 7.2.2 | Port I/O | 304 |
| 7.3 | Direct Memory Access (DMA) | 308 |
| 7.3.1 | PCI DMA interface | 310 |
| 7.3.2 | Example: Sending a network packet | 315 |
| 7.3.3 | IA-64 implementation | 317 |
| 7.4 | Device Interrupts | 318 |
| 7.4.1 | IA-64 hardware interrupt architecture | 320 |
| 7.4.2 | Device interrupt interface | 326 |
| 7.4.3 | Interrupt handling | 332 |
| 7.4.4 | Managing the IA-64 interrupt steering logic | 334 |
| 7.5 | Summary | 335 |
| 8 | SYMMETRIC MULTIPROCESSING | 337 |
| 8.1 | Introduction to Multiprocessing on Linux | 337 |
| 8.2 | Linux Locking Principles | 339 |
| 8.2.1 | Locking rules | 341 |
| 8.2.2 | The big kernel lock (BKL) | 342 |
| 8.3 | Multiprocessor Support Interface | 344 |
| 8.3.1 | Support facilities | 345 |
| 8.3.2 | IA-64 implementation | 348 |
| 8.4 | CPU-Specific Data Area | 352 |
| 8.4.1 | False sharing | 353 |
| 8.4.2 | Virtual mapping of CPU-specific data area | 355 |
| 8.5 | Tracking Wall-Clock Time with High Resolution | 356 |
| 8.5.1 | MP challenges and options in maintaining wall-clock time | 356 |
| 8.5.2 | Synchronizing the cycle counters in an MP machine | 357 |
| 8.6 | Summary | 361 |
| 9 | UNDERSTANDING SYSTEM PERFORMANCE | 363 |
| 9.1 | IA-64 Performance Monitoring Unit Overview | 366 |
| 9.1.1 | PMU register file | 366 |
| 9.1.2 | Controlling monitoring | 372 |
| 9.1.3 | Dealing with counter overflows | 373 |
| 9.2 | Extending the PMU: The Itanium Example | 375 |
| 9.2.1 | Itanium PMU additional capabilities | 375 |
| 9.2.2 | Itanium PMU register file | 376 |
| 9.2.3 | Itanium PMU events | 377 |
| 9.2.4 | Hardware support for event sampling | 378 |
| 9.2.5 | Event address registers (EAR) | 381 |
| 9.2.6 | Branch trace buffer (BTB) | 384 |
| 9.2.7 | Miscellaneous features | 388 |
| 9.3 | Kernel Support for Performance Monitoring | 390 |
| 9.3.1 | The perfmon interface | 392 |
| 9.3.2 | Implementation aspects | 399 |
| 9.3.3 | Using the perfmon interface: The pfmon example | 405 |
| 9.4 | Summary | 407 |
| 10 | BOOTING | 409 |
| 10.1 | IA-64 Firmware Overview | 410 |
| 10.1.1 | Processor Abstraction Layer (PAL) | 411 |
| 10.1.2 | System Abstraction Layer (SAL) | 417 |
| 10.1.3 | Advanced configuration and power interface (ACPI) | 422 |
| 10.1.4 | Extensible firmware interface (EFI) | 426 |
| 10.2 | The Bootloader | 435 |
| 10.2.1 | Loading the kernel image | 436 |
| 10.2.2 | Loading the initial RAM disk | 437 |
| 10.2.3 | Loading the FPSWA | 438 |
| 10.2.4 | Collecting the boot parameters | 438 |
| 10.2.5 | Starting the kernel | 439 |
| 10.3 | Kernel Initialization | 441 |
| 10.3.1 | The bootstrap interface | 441 |
| 10.3.2 | IA-64 implementation | 445 |
| 10.4 | Summary | 448 |
| 11 | IA-32 COMPATIBILITY | 449 |
| 11.1 | Architectural Support for IA-32 | 450 |
| 11.1.1 | IA-32 user-level machine state | 451 |
| 11.1.2 | Mapping the IA-32 user-level machine state to IA-64 | 452 |
| 11.1.3 | IA-32 segmentation and memory addressing | 454 |
| 11.1.4 | Transferring control between IA-32 and IA-64 | 456 |
| 11.2 | Linux Support for IA-32 Applications | 457 |
| 11.2.1 | Kernel representation of an IA-32 task | 459 |
| 11.2.2 | Address space of an emulated IA-32 task | 459 |
| 11.2.3 | Dealing with absolute filesystem paths | 463 |
| 11.2.4 | Starting an IA-32 executable | 465 |
| 11.2.5 | System call emulation | 469 |
| 11.2.6 | Signal delivery | 479 |
| 11.2.7 | Accessing I/O port space | 480 |
| 11.3 | Summary | 481 |
| A IA-64 CPU MODELS | 483 |
| B KERNEL REGISTER USAGE | 484 |
| C IA-64 INSTRUCTIONS | 485 |
| C.1 | Integer Instructions | 485 |
| C.2 | Memory Instructions | 487 |
| C.3 | Semaphore Instructions | 487 |
| C.4 | Branch Instructions | 487 |
| C.5 | Control Instructions | 488 |
| C.6 | Multimedia Instructions | 488 |
| C.7 | Floating-Point Instructions | 489 |
| C.8 | Privileged Instructions | 490 |
| D ITANIUM PMU EVENTS | 491 |
| E GLOSSARY | 495 |
| BIBLIOGRAPHY | 499 |
| INDEX | 505 |