OS note - modrpc/info GitHub Wiki

Table of Contents

General

LAB #0

  • Install/try XV6
  • prerequisites:
    • GMP: GNU MP bignum library
    • MPFR: GNU multi-precison floating-point computation with correct rounding
    • MPC:GNU C library for complex numbers with arbitrary high precision and correct rounding,
  • nm kernel: list symbols from object files
$ nm kernel | grep _start   # find the entry point of kernel
8010a48c D _binary_entryother_start
8010a460 D _binary_initcode_start
0010000c T _start

LAB #1

QEMU

qemu-system-i386 \
    -drive file=obj/kern/kernel.img,index=0,media=disk,format=raw \
    -serial mon:stdio \
    -gdb tcp::26000 \
    -D qemu.log
  • -serial mon:stdio: Connect "mon:stdio" to serial port so that XTERM terminal can MIRROR the console of QEMU VM
  • -gdb tcp::26000: QEMU will create a GDB server which GDB client can connect and control execution

Compilation of Boot sector

  • Compile:
    • gcc -pipe -nostdinc -O1 -fno_builtin -I. -MD -fno_omit_frame_pointer -Wno_format -gstabs -m32 -fno_stack_protector -DJOS_KERNEL -c -o boot.o boot.S
    • gcc -pipe -nostdinc -O1 -fno_builtin -I. -MD -fno_omit_frame_pointer -Wno_format -gstabs -m32 -fno_stack_protector -DJOS_KERNEL -Os -c -o main.o main.c
      • -pipe: faster compilation (w/o temp file)
      • -nostdinc: don't include standard C include (no. stdlibc in kernel)
      • -fno_omit_frame_pointer: auto ON for x86_64 when -On given; expclitly if x86 (.386)
  • Load:
    • ld -m elf_i386 -N -e start -Ttext 0x7c00 -o boot.out boot.o main.o
      • -N: set text/data sector RW
      • -e start: entry point
      • -Ttext 0x7c00: text sector start at 0x7c00
    • objdump -S boot.out > boot.asm
    • objcopy -S -o binary -j .text boot.out boot
      • -j .text: copy only text sector
  • Sanity check

Object Files

  • text section: objdump -h obj/boot/boot.out
obj/boot/boot.out:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000186  00007c00  00007c00  00000074  2**2
                  CONTENTS, ALLOC, LOAD, CODE
  1 .eh_frame     000000a8  00007d88  00007d88  000001fc  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .stab         00000720  00000000  00000000  000002a4  2**2
                  CONTENTS, READONLY, DEBUGGING
  3 .stabstr      0000088f  00000000  00000000  000009c4  2**0
                  CONTENTS, READONLY, DEBUGGING
  4 .comment      00000034  00000000  00000000  00001253  2**0
                  CONTENTS, READONLY
  • program headers: objdump -x obj/boot/boot.out
obj/boot/boot.out:     file format elf32-i386
obj/boot/boot.out
architecture: i386, flags 0x00000012:
EXEC_P, HAS_SYMS
start address 0x00007c00

Program Header:
    LOAD off    0x00000074 vaddr 0x00007c00 paddr 0x00007c00 align 2**2
         filesz 0x00000230 memsz 0x00000230 flags rwx
   STACK off    0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**4
         filesz 0x00000000 memsz 0x00000000 flags rwx

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000186  00007c00  00007c00  00000074  2**2
                  CONTENTS, ALLOC, LOAD, CODE
  1 .eh_frame     000000a8  00007d88  00007d88  000001fc  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .stab         00000720  00000000  00000000  000002a4  2**2
                  CONTENTS, READONLY, DEBUGGING
  3 .stabstr      0000088f  00000000  00000000  000009c4  2**0
                  CONTENTS, READONLY, DEBUGGING
  4 .comment      00000034  00000000  00000000  00001253  2**0
                  CONTENTS, READONLY
SYMBOL TABLE:
00007c00 l    d  .text  00000000 .text
00007d88 l    d  .eh_frame      00000000 .eh_frame
00000000 l    d  .stab  00000000 .stab
00000000 l    d  .stabstr       00000000 .stabstr
00000000 l    d  .comment       00000000 .comment
00000000 l    df *ABS*  00000000 main.c
00000000 l    df *ABS*  00000000 obj/boot/boot.o
00000008 l       *ABS*  00000000 PROT_MODE_CSEG
00000010 l       *ABS*  00000000 PROT_MODE_DSEG
00000001 l       *ABS*  00000000 CR0_PE_ON
00007c0a l       .text  00000000 seta20.1
00007c14 l       .text  00000000 seta20.2
00007c64 l       .text  00000000 gdtdesc
00007c32 l       .text  00000000 protcseg
00007c4a l       .text  00000000 spin
00007c4c l       .text  00000000 gdt
00007c6a g     F .text  00000012 waitdisk
00007d15 g     F .text  00000071 bootmain
00007cdc g     F .text  00000039 readseg
00007e30 g       .eh_frame      00000000 __bss_start
00007c7c g     F .text  00000060 readsect
00007e30 g       .eh_frame      00000000 _edata
00007e30 g       .eh_frame      00000000 _end
00007c00 g       .text  00000000 start

Boot

  • Some memory address range mapps to BIOS ROM.
  • On boot, PC points to (hardwired) an address in BIOS ROM. BIOS contains code which does:
    • set up IDT (interrupt descriptor table)
    • initalizes PCI bus
    • initalizes devices that BIOS knows (console -- VGA display, keyboard, etc.)
    • search for bootable device -- floppy, HDD, CD-ROM
    • from a bootable device, reads the boot loader (e.g. the "boot" sector 0 in HDD) into memory
    • jump to the memory (i.e. execute boot loader) -- bootloader will read the kernel image into the memory.

ELF

  • starts with fixed-length ELF header, followed by variable-length program header
  • program header lists each of program sections to be loaded
  • program sections are:
    • .text: The program's executable instructions.
    • .rodata: Read-only data, such as ASCII string constants produced by the C compiler. (We will not bother setting up the hardware to prohibit writing, however.)
    • .data: The data section holds the program's initialized data, such as global variables declared with initializers like int x = 5;.
  • When linker computes a memory layout, it reserved space for uninitialized global vars (i.e. .bss) that follows .data in memory.
  • LMA (load address) vs VMA (link address) in .text section
    • LMA: memory address at which the section should be loaded into memory
    • VMA: the memory address from which the section expects to execute
      • unless PIC (position-independent code). which does not contain any absolute addresses, LMA should be respected
      • typically, VMA and LMA are the same

How Boot Loader "LOADs" Kernel

void
bootmain(void)
{
        struct Proghdr *ph, *eph;
        // read 1st page off disk
        readseg((uint32_t) ELFHDR, SECTSIZE*8, 0);

        // is this a valid ELF?
        if (ELFHDR->e_magic != ELF_MAGIC)
          goto bad;

        // load each program segment (ignores ph flags)
        ph = (struct Proghdr *) ((uint8_t *) ELFHDR + ELFHDR->e_phoff);
        eph = ph + ELFHDR->e_phnum;
        for (; ph < eph; ph++)
          // p_pa is the load address of this segment (as well
          // as the physical address)
          readseg(ph->p_pa, ph->p_memsz, ph->p_offset);

        // call the entry point from the ELF header
        // note: does not return!
        ((void (*)(void)) (ELFHDR->e_entry))();

bad:
        outw(0x8A00, 0x8A00);
        outw(0x8A00, 0x8E00);
        while (1)
          /* do nothing */

Kernel

  • load addresses and link addresses are not the same in kernel
    • kernel tells the boot lader to load it into memory at a low address (1MB) but it expects to execute from a high address
  • objdump -h obj/kern/kernel
obj/kern/kernel:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00001d81  f0100000  00100000  00001000  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .rodata       000009a8  f0101da0  00101da0  00002da0  2**5
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .stab         00004555  f0102748  00102748  00003748  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .stabstr      00001cbb  f0106c9d  00106c9d  00007c9d  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .data         0000a300  f0109000  00109000  0000a000  2**12
                  CONTENTS, ALLOC, LOAD, DATA
  5 .bss          00000650  f0113300  00113300  00014300  2**5
                  ALLOC
  6 .comment      00000034  00000000  00000000  00014300  2**0
                  CONTENTS, READONLY
  • entry point in ELF header: objdump -x obj/kern/kernel
obj/kern/kernel:     file format elf32-i386
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x0010000c

Setting up Kernel Memory

Entry Page Table Setup

  • kern/entrypgdir.c: page table setup
    • For now, this only maps first 4MB of physical memory
    • "mapping physical memory" means: creating a page table for some "virtual addres space" which will be mapped to first 4MB
    • i.e. we have 4MB physical memory to use; now we make a plan how to use the 4MB physical memory
    • The mapping is not necessarily 1-to-1; many-to-1 is ok.
  • maps virtual addresses [KERNBASE,]KERNBASE+4MB) to physical addresses [0,]4MB)
    • KERNBASE = 0xF000-0000
    • WHY 4MG?: 4MB is enough to be mapped using "one" page table

Page Directory

  • kern/entry.S:
    • Load the physical address of entry_pgdir into cr3
      • movl $(RELOC(entry_pgdir)), %eax
      • movl %eax, %cr3
    • Turn on paging
      • movl %cr0, %eax
      • movl $(CR0_PE&amp;&#35;124&#59;CR0_PG&amp;&#35;124&#59;CR0_WP), %eax
      • movl %eax, %cr0
__attribute__((__aligned__(PGSIZE)))
pde_t entry_pgdir[NPDENTRIES] = {
  // Map VA's [0, 4MB) to PA's [0, 4MB)
  [0]
      = ((uintptr_t)entry_pgtable - KERNBASE) + PTE_P,
  // Map VA's [KERNBASE, KERNBASE+4MB) to PA's [0, 4MB)
  [KERNBASE>>PDXSHIFT]
      = ((uintptr_t)entry_pgtable - KERNBASE) + PTE_P + PTE_W
};

Page Table

  • Page table entry consists of page table entries
  • Entry 0 of the page table maps to physical page 0, entry 1 to physical page 1, etc.
pte_t entry_pgtable[NPTENTRIES] = {
        0x000000 | PTE_P | PTE_W,
        0x001000 | PTE_P | PTE_W
};

Formatted Printing to Console

  • kern/console.c: cga, keybard, serial

Stacks

GCC X86 Calling Convention

CALL: Walkthrough

Initial status

  • Before call: during execution of a function; caller needs to call another function
    |                 |
    +-----------------+
    |  saved %ebp     | <---- %ebp
    +-----------------+ 
    |  local var      | 
    +-----------------+ 
    |  local var      | 
    +-----------------+ 
    |  callee-save Rs | <---- %esp            STACK FRAME for current function
    +-----------------+-------------------------------------------------------
    |                 | 
    +-----------------+

CALLER: BEFORE the CALL

  • Caller push arguments & caller-save registers: Frst argument comes last
caller:
        pushl   %ebp            # make new call frame
        movl    %esp, %ebp

        pushl   3               # push arguments
        pushl   2
        pushl   1

        call    callee          # call callee

        add     %esp, 12        # remove arguments from frame

        add     %eax, 5         # use result  (%eax contains return value)
        popl    %ebp            # restore old call frame

        ret                     # return
    |                 |
    +-----------------+
    |  saved %ebp     | <---- %ebp
    +-----------------+ 
    |  local var      | 
    +-----------------+ 
    |  local var      | 
    +-----------------+ 
    |  callee-save Rs |                       STACK FRAME for current function
    +-----------------+ - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    |  arg n          |                       STACK FRAME for current function
    +-----------------+                                 extended for call
    |  ...            |
    +-----------------+
    |  arg 0          | <---- %esp            STACK FRAME for current function
    +-----------------+--------------------------------------------------------

CALLER: CALL instruction

  • CALL instruction is executed: x86 will push the %eip (i.e. address of next instruction after "call foo") into stack and then jump to CALLEE
    |                 |
    +-----------------+
    |  saved %ebp     | <---- %ebp
    +-----------------+ 
    |  local var      | 
    +-----------------+ 
    |  local var      |                       
    +-----------------+ 
    |  callee-save Rs |                       STACK FRAME for current function
    +-----------------+ - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    |  arg n          |                       STACK FRAME for current function
    +-----------------+                                  extended for call
    |  ...            |
    +-----------------+
    |  arg 0          | 
    +-----------------+
    |  return %eip    | <---- %esp            STACK FRAME for current function
    +-----------------+-------------------------------------------------------

CALEE: CALLEE starts

  • Call executed at text section: at this point following contract between CALLER and CALLEE
    • at entry to a function (i.e. just after call):
      • %eip points at first instruction of function
      • %esp+4 points at first argument
      • %esp points at return address
    • after ret instruction:
      • %eip contains return address
      • %esp points at arguments pushed by caller
      • called function may have trashed arguments
      • %eax (and %edx, if return type is 64-bit) contains return value (or trash if function is void)
      • %eax, %edx (above), and %ecx may be trashed
      • %ebp, %ebx, %esi, %edi must contain contents from time of call
    • Terminology:
      • %eax, %ecx, %edx are "caller save" registers
      • %ebp, %ebx, %esi, %edi are "callee save" registers

CALLEE: prologue

  • Function prologue: caller do this upon entry
pushl %ebp          # save frame pointer into stack
                    # so that new value can be set to %ebp
movl  %esp, %ebp    # set new frame pointer;
                    # current esp becomes ebp

                    # above two instructions = "enter $0, $0"

subl  $80, %esp     # allocate stack space (local vars)

pushl %edi          # save callee-save registers
pushl %esi          # save callee-save registers
pushl %ebx          # (in case they are used in function)
  • Callee executes prologue; prologue updates the stack as follows
    |                 |
    +-----------------+
    |  saved %ebp     | <---- [OLD %ebp]
    +-----------------+ 
    |  local var      | 
    +-----------------+ 
    |  local var      |                       
    +-----------------+ 
    |  callee-save Rs |                       STACK FRAME for current function
    +-----------------+ - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    |  arg n          |                       STACK FRAME for current function
    +-----------------+                                  extended for call
    |  ...            | 
    +-----------------+
    |  arg 0          | 
    +-----------------+
    |  return %eip    | <---- [OLD %esp]      STACK FRAME for current function
    +-----------------+-------------------------------------------------------
    |  OLD %ebp       | <---- %ebp      (pushl OLD %ebp; and then curr %esp becomes %ebp)
    +-----------------+ 
    |  local var      | 
    +-----------------+
    |  local var      |
    +-----------------+
    |  callee-save Rs | <---- %esp
    +-----------------+

CALLEE: epliogue

  • Function epilogue: callee do this before return
movl  %edi, %eax    # set up return value

popl  %ebx          # restore callee-save registers
popl  %esi          # restore callee-save registers
popl  %edi          # restore callee-save registers

movl  %ebp, %esp    # restore stack pointer
popl  %ebp          # restore frame pointer 
                    # above two instructions = "leave"

return              # pop return address

CALLEE: before return

  • Callee executes prologue; prologue updates the stack as follows
    • pop calle--save registers
    |                 |
    +-----------------+
    |  saved %ebp     | <---- [OLD %ebp]
    +-----------------+ 
    |  local var      | 
    +-----------------+ 
    |  local var      |                       STACK FRAME for current function
    +-----------------+ - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    |  arg n          |                       STACK FRAME for current function
    +-----------------+                                  extended
    |  ...            |
    +-----------------+
    |  arg 0          | 
    +-----------------+
    |  return %eip    | <---- [OLD %esp]      STACK FRAME for current function
    +-----------------+-------------------------------------------------------
    |  OLD %ebp       | <---- %ebp      (pushl OLD %ebp; and then curr %esp becomes %ebp)
    +-----------------+ 
    |  local var      | 
    +-----------------+
    |  local var      | <---- %esp
    +-----------------+
    • "leave": restore stack poitner and frame pointer
    |                 |
    +-----------------+
    |  saved %ebp     | <---- %ebp
    +-----------------+ 
    |  local var      | 
    +-----------------+ 
    |  local var      |                       STACK FRAME for current function
    +-----------------+ - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    |  arg n          |                       STACK FRAME for current function
    +-----------------+                                  extended
    |  ...            |
    +-----------------+
    |  arg 0          | 
    +-----------------+
    |  return %eip    | <---- %esp 
    +-----------------+
    • return: pop return $eip
    |                 |
    +-----------------+
    |  saved %ebp     | <---- %ebp
    +-----------------+ 
    |  local var      | 
    +-----------------+ 
    |  local var      |                       STACK FRAME for current function
    +-----------------+ - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    |  arg n          |                       STACK FRAME for current function
    +-----------------+                                  extended
    |  ...            |
    +-----------------+
    |  arg 0          | <---- %esp
    +-----------------+

CALLER: after return

  • adjust %esp for arguments
  • use return value inside %eax

Example

  • C code
              int main(void) { return f(8)+1; }
              int f(int x) { return g(x); }
              int g(int x) { return x+3; }
  • Assembler
            _main :
                                      prologue
                      pushl %ebp
                      movl %esp, %ebp
                                      body
                      pushl $8
                      call _f
                      addl $1, %eax
                                      epilogue
                      movl %ebp, %esp
                      popl %ebp
                      ret
              _f :
                                      prologue
                      pushl %ebp
                      movl %esp, %ebp
                                      body
                      pushl 8(%esp)
                      call _g
                                      epilogue
                      movl %ebp, %esp
                      popl %ebp
                      ret

              _g :
                                      prologue
                      pushl %ebp
                      movl %esp, %ebp
                                      save %ebx
                      pushl %ebx
                                      body
                      movl 8(%ebp), %ebx
                      addl $3, %ebx
                      movl %ebx, %eax
                                      restore %ebx
                      popl %ebx
                                      epilogue
                      movl %ebp, %esp
                      popl %ebp
                      ret

LAB #2

Overview

  • Two things to do for memory management: 1) physical memory allocation and 2) virtual memory
  • physical memory allocator: allows kernel to allocate/free memory (in 4KB-pages)
    • need to maintain table to see which physical pages are free/allocated
  • virtual memory: maps virtual addresses used by kernel and user to physical memory
    • x86 MMU performs address translation, based on "page directory and page tables"
    • so, supporting virtual memory essentially means populating the page dir/tables

Physical Memory Allocator

  • Two memory allocators are needed:
    • boot_alloc() to be used right AFTER booting and BEFORE setting up virtual memory
    • page_alloc()/page_free() to be used after setting up virtual memory

mem_init(): Memory initialization

  1. i386_detect_memory()
    1. determine basemem, extmem, npages
  2. Create initial page directory, insert kern_pgdir into page directory itself (at PDX(UVPT))
    1. kern_pgdir = (pde_t *) boot_alloc(PGSIZE)
    2. kern_pgdir[PDX(UVPT)] = PADDR(kern_pgdir) | PTE_U | PTE_P
  3. Create pages = boot_alloc(npages * sizeof(struct PageInfo))

BOOT_ALLOC

  • Will allocate two stuffs: kern_pgdir, PageInfo array
  • kern_pgdir: initial page directory (size=PGSiZE=4096); so that the PDX(UVPT) entry recursively points to itself.
 kern_pgdir[PDX(UVPT)] = PADDR(kern_pgdir) | PTE_U | PTE_P
  • <npages></npages> PageInfo objects: i.e. there are 4096 * npages pages; npages are the number of pages in physical memory
    (computed during bootup)
K> kerninfo
 _start                    0010000c (phys)
 entry    f010000c (virt)  0010000c (phys)
 etext    f0101e11 (virt)  00101e11 (phys)
 edata    f0113300 (virt)  00113300 (phys)
 end      f0113950 (virt)  00113950 (phys)

PAGE_ALLOC

Virtual, Linear, Physical addresses

  • Address types:
    • uintptr_t: opaque virtual address; only virtual addresses can be dereferenced
      • this is because, "dereferencing" means going through MMU for address translation; physical addresses are OUTPUT of MMU not INPUT of MMU
    • physaddr_t: physical address; physical addresses can never be dereferenced

Page tables

  • 32-bit address can have up-to-4GB byte-addressable memory.
  • let the size of a page be 4KB
    • i.e. there are 4GB/4KB = 1M pages in 4GB memory
  • simple 1-dimensional page table:
    • for each of 2^20 = 1M pages, create one table entry.
    • there are 1M page table entry, where each entry occupies 4B (total 4MB) -- 4B points the physical address where the page starts
  • 2-level paging scheme
  • fragment the giant 1M-entry page table into many page tables (1024 tables) and one page directory (1024 entries).

Why UVPT?

  • We'd like to get the giant conceptual page-table back in some way -- processes in JOS are going to look at it to figure out what's going on in their address space. But how?
  • Luckily, the paging hardware is great for precisely this -- putting together a set of fragmented pages into a contiguous address space. And it turns out we already have a table with pointers to all of our fragmented page tables: it's the page directory!
  • So, we can use the page directory as a page table to map our conceptual giant 2^22-byte page table (represented by 1024 pages) at some contiguous 2^22-byte range in the virtual address space. And we can ensure user processes can't modify their page tables by marking the PDE entry as read-only.
  • Puzzle: do we need to create a separate UVPD mapping too?
  • CR3 points at the page directory.
    • The PDX part of the address indexes into the page directory to give you a page table.
    • The PTX part indexes into the page table to give you a page, and then you add the low bits in.
  • But the processor has no concept of page directories, page tables, and pages being anything other than plain memory.
    • So there's nothing that says a particular page in memory can't serve as two or three of these at once.
    • The processor just follows pointers: pd = lcr3(); pt = *(pd+4*PDX); page = *(pt+4*PTX);
  • Diagramatically, it starts at CR3, follows three arrows, and then stops.
  • If we put a pointer into the page directory that points back to itself at index V, as in
  • then when we try to translate a virtual address with PDX and PTX equal to V, following three arrows leaves us at the page directory. So that virtual page translates to the page holding the page directory. In Jos, V is 0x3BD, so the virtual address of the UVPD is (0x3BD<<22)|(0x3BD<<12).
  • Now, if we try to translate a virtual address with PDX = V but an arbitrary PTX != V, then following three arrows from CR3 ends one level up from usual (instead of two as in the last case), which is to say in the page tables. So the set of virtual pages with PDX=V form a 4MB region whose page contents, as far as the processor is concerned, are the page tables themselves. In Jos, V is 0x3BD so the virtual address of the UVPT is (0x3BD<<22).
  • So because of the "no-op" arrow we've cleverly inserted into the page directory, we've mapped the pages being used as the page directory and page table (which are normally virtually invisible) into the virtual address space.

Virtual Memory Layout

/*
 * Virtual memory map:                                Permissions
 *                                                    kernel/user
 *
 *    4 Gig -------->  +------------------------------+
 *                     |                              | RW/--
 *                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *                     :              .               :
 *                     :              .               :
 *                     :              .               :
 *                     |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| RW/--
 *                     |                              | RW/--
 *                     |   Remapped Physical Memory   | RW/--
 *                     |                              | RW/--
 *    KERNBASE, ---->  +------------------------------+ 0xf0000000      --+
 *    KSTACKTOP        |     CPU0's Kernel Stack      | RW/--  KSTKSIZE   |
 *                     | - - - - - - - - - - - - - - -|                   |
 *                     |      Invalid Memory (*)      | --/--  KSTKGAP    |
 *                     +------------------------------+                   |
 *                     |     CPU1's Kernel Stack      | RW/--  KSTKSIZE   |
 *                     | - - - - - - - - - - - - - - -|                 PTSIZE
 *                     |      Invalid Memory (*)      | --/--  KSTKGAP    |
 *                     +------------------------------+                   |
 *                     :              .               :                   |
 *                     :              .               :                   |
 *    MMIOLIM ------>  +------------------------------+ 0xefc00000      --+
 *                     |       Memory-mapped I/O      | RW/--  PTSIZE
 * ULIM, MMIOBASE -->  +------------------------------+ 0xef800000
 *                     |  Cur. Page Table (User R-)   | R-/R-  PTSIZE
 *    UVPT      ---->  +------------------------------+ 0xef400000
 *                     |          RO PAGES            | R-/R-  PTSIZE
 *    UPAGES    ---->  +------------------------------+ 0xef000000
 *                     |           RO ENVS            | R-/R-  PTSIZE
 * UTOP,UENVS ------>  +------------------------------+ 0xeec00000
 * UXSTACKTOP -/       |     User Exception Stack     | RW/RW  PGSIZE
 *                     +------------------------------+ 0xeebff000
 *                     |       Empty Memory (*)       | --/--  PGSIZE
 *    USTACKTOP  --->  +------------------------------+ 0xeebfe000
 *                     |      Normal User Stack       | RW/RW  PGSIZE
 *                     +------------------------------+ 0xeebfd000
 *                     |                              |
 *                     |                              |
 *                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *                     .                              .
 *                     .                              .
 *                     .                              .
 *                     |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
 *                     |     Program Data & Heap      |
 *    UTEXT -------->  +------------------------------+ 0x00800000
 *    PFTEMP ------->  |       Empty Memory (*)       |        PTSIZE
 *                     |                              |
 *    UTEMP -------->  +------------------------------+ 0x00400000      --+
 *                     |       Empty Memory (*)       |                   |
 *                     | - - - - - - - - - - - - - - -|                   |
 *                     |  User STAB Data (optional)   |                 PTSIZE
 *    USTABDATA ---->  +------------------------------+ 0x00200000        |
 *                     |       Empty Memory (*)       |                   |
 *    0 ------------>  +------------------------------+                 --+
 *
 * (*) Note: The kernel ensures that "Invalid Memory" is *never* mapped.
 *     "Empty Memory" is normally unmapped, but user programs may map pages
 *     there if desired.  JOS user programs map pages temporarily at UTEMP.
 */

LAB #3

ELF format

  • Two views: one for linking and the other for execution

Interrupts

            CPU0       CPU1       CPU2       CPU3       
   0:         24          0          0          0  IR-IO-APIC    2-edge      timer
   1:          5          3          1          2  IR-IO-APIC    1-edge      i8042
   7:         14          0          0          0  IR-IO-APIC    7-edge    
   8:          0          0          0          1  IR-IO-APIC    8-edge      rtc0
   9:          0          0          0          0  IR-IO-APIC    9-fasteoi   acpi
  12:         12          0          0          1  IR-IO-APIC   12-edge      i8042
  16:          0          0          0          0  IR-IO-APIC   16-fasteoi   rtl_pci
  17:         31        557         67        333  IR-IO-APIC   17-fasteoi   snd_hda_intel
 120:          0          0          0          0  DMAR-MSI    0-edge      dmar0
 121:          0          0          0          0  IR-PCI-MSI 16384-edge      PCIe PME
 122:          0          0          0          0  IR-PCI-MSI 458752-edge      PCIe PME
 123:          0          0          0          0  IR-PCI-MSI 466944-edge      PCIe PME
 124:          0          0          0          0  IR-PCI-MSI 471040-edge      PCIe PME
 125:       6623    1147264      14748    3021727  IR-PCI-MSI 327680-edge      xhci_hcd
 126:       9400      24084      32778     558090  IR-PCI-MSI 376832-edge      0000:00:17.0
 127:          0    8978004      24983    5453710  IR-PCI-MSI 2097152-edge      enp4s0
 128:         16          0          9          1  IR-PCI-MSI 360448-edge      mei_me
 129:        130        272        151         59  IR-PCI-MSI 514048-edge      snd_hda_intel
 130:        106       6627    3223903         43  IR-PCI-MSI 524288-edge      nvidia
 NMI:        340        352        347        357   Non-maskable interrupts
 LOC:    9377514    8925961    8306858    9074815   Local timer interrupts
 SPU:          0          0          0          0   Spurious interrupts
 PMI:        340        352        347        357   Performance monitoring interrupts
 IWI:          0          0          0          1   IRQ work interrupts
 RTR:          3          0          0          0   APIC ICR read retries
 RES:    2368415    1729579    1839443    1729691   Rescheduling interrupts
 CAL:      56806      10619      11076       9979   Function call interrupts
 TLB:     736667     747816     709980     730346   TLB shootdowns
 TRM:          1          1          1          1   Thermal event interrupts
 THR:          0          0          0          0   Threshold APIC interrupts
 DFR:          0          0          0          0   Deferred Error APIC interrupts
 MCE:          0          0          0          0   Machine check exceptions
 MCP:        271        271        271        271   Machine check polls
 ERR:         14
 MIS:          0
 PIN:          0          0          0          0   Posted-interrupt notification event
 PIW:          0          0          0          0   Posted-interrupt wakeup event
⚠️ **GitHub.com Fallback** ⚠️