| 1 | #include "asm.h" |
| 2 | #include "memlayout.h" |
| 3 | #include "mmu.h" |
| 4 | |
| 5 | # Each non-boot CPU ("AP") is started up in response to a STARTUP |
| 6 | # IPI from the boot CPU. Section B.4.2 of the Multi-Processor |
| 7 | # Specification says that the AP will start in real mode with CS:IP |
| 8 | # set to XY00:0000, where XY is an 8-bit value sent with the |
| 9 | # STARTUP. Thus this code must start at a 4096-byte boundary. |
| 10 | # |
| 11 | # Because this code sets DS to zero, it must sit |
| 12 | # at an address in the low 2^16 bytes. |
| 13 | # |
| 14 | # Startothers (in main.c) sends the STARTUPs one at a time. |
| 15 | # It copies this code (start) at 0x7000. It puts the address of |
| 16 | # a newly allocated per-core stack in start-4,the address of the |
| 17 | # place to jump to (mpenter) in start-8, and the physical address |
| 18 | # of entrypgdir in start-12. |
| 19 | # |
| 20 | # This code combines elements of bootasm.S and entry.S. |
| 21 | |
| 22 | .code16 |
| 23 | .globl start |
| 24 | start: |
| 25 | cli |
| 26 | |
| 27 | # Zero data segment registers DS, ES, and SS. |
| 28 | xorw %ax,%ax |
| 29 | movw %ax,%ds |
| 30 | movw %ax,%es |
| 31 | movw %ax,%ss |
| 32 | |
| 33 | # Switch from real to protected mode. Use a bootstrap GDT that makes |
| 34 | # virtual addresses map directly to physical addresses so that the |
| 35 | # effective memory map doesn't change during the transition. |
| 36 | lgdt gdtdesc |
| 37 | movl %cr0, %eax |
| 38 | orl $CR0_PE, %eax |
| 39 | movl %eax, %cr0 |
| 40 | |
| 41 | # Complete the transition to 32-bit protected mode by using a long jmp |
| 42 | # to reload %cs and %eip. The segment descriptors are set up with no |
| 43 | # translation, so that the mapping is still the identity mapping. |
| 44 | ljmpl $(SEG_KCODE<<3), $(start32) |
| 45 | |
| 46 | //PAGEBREAK! |
| 47 | .code32 # Tell assembler to generate 32-bit code now. |
| 48 | start32: |
| 49 | # Set up the protected-mode data segment registers |
| 50 | movw $(SEG_KDATA<<3), %ax # Our data segment selector |
| 51 | movw %ax, %ds # -> DS: Data Segment |
| 52 | movw %ax, %es # -> ES: Extra Segment |
| 53 | movw %ax, %ss # -> SS: Stack Segment |
| 54 | movw $0, %ax # Zero segments not ready for use |
| 55 | movw %ax, %fs # -> FS |
| 56 | movw %ax, %gs # -> GS |
| 57 | |
| 58 | # Turn on page size extension for 4Mbyte pages |
| 59 | movl %cr4, %eax |
| 60 | orl $(CR4_PSE), %eax |
| 61 | movl %eax, %cr4 |
| 62 | # Use entrypgdir as our initial page table |
| 63 | movl (start-12), %eax |
| 64 | movl %eax, %cr3 |
| 65 | # Turn on paging. |
| 66 | movl %cr0, %eax |
| 67 | orl $(CR0_PE|CR0_PG|CR0_WP), %eax |
| 68 | movl %eax, %cr0 |
| 69 | |
| 70 | # Switch to the stack allocated by startothers() |
| 71 | movl (start-4), %esp |
| 72 | # Call mpenter() |
| 73 | call *(start-8) |
| 74 | |
| 75 | movw $0x8a00, %ax |
| 76 | movw %ax, %dx |
| 77 | outw %ax, %dx |
| 78 | movw $0x8ae0, %ax |
| 79 | outw %ax, %dx |
| 80 | spin: |
| 81 | jmp spin |
| 82 | |
| 83 | .p2align 2 |
| 84 | gdt: |
| 85 | SEG_NULLASM |
| 86 | SEG_ASM(STA_X|STA_R, 0, 0xffffffff) |
| 87 | SEG_ASM(STA_W, 0, 0xffffffff) |
| 88 | |
| 89 | |
| 90 | gdtdesc: |
| 91 | .word (gdtdesc - gdt - 1) |
| 92 | .long gdt |
| 93 | |
| 94 | |