qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

boot.S (6146B)


      1 /*
      2  * x86_64 boot and support code
      3  *
      4  * Copyright 2019 Linaro
      5  *
      6  * This work is licensed under the terms of the GNU GPL, version 3 or later.
      7  * See the COPYING file in the top-level directory.
      8  *
      9  * Unlike the i386 version we instead use Xen's PVHVM booting header
     10  * which should drop us automatically into 32 bit mode ready to go. I've
     11  * nabbed bits of the Linux kernel setup to achieve this.
     12  *
     13  * SPDX-License-Identifier: GPL-3.0-or-later
     14  */
     15 
     16         .section .head
     17 
     18 #define ELFNOTE_START(name, type, flags)	\
     19 .pushsection .note.name, flags,@note	;	\
     20   .balign 4				;	\
     21   .long 2f - 1f		/* namesz */	;	\
     22   .long 4484f - 3f	/* descsz */	;	\
     23   .long type				;	\
     24 1:.asciz #name				;	\
     25 2:.balign 4				;	\
     26 3:
     27 
     28 #define ELFNOTE_END				\
     29 4484:.balign 4				;	\
     30 .popsection				;
     31 
     32 #define ELFNOTE(name, type, desc)		\
     33 	ELFNOTE_START(name, type, "")		\
     34 		desc			;	\
     35 	ELFNOTE_END
     36 
     37 #define XEN_ELFNOTE_ENTRY          1
     38 #define XEN_ELFNOTE_HYPERCALL_PAGE 2
     39 #define XEN_ELFNOTE_VIRT_BASE      3
     40 #define XEN_ELFNOTE_PADDR_OFFSET   4
     41 #define XEN_ELFNOTE_PHYS32_ENTRY  18
     42 
     43 #define __ASM_FORM(x)	x
     44 #define __ASM_SEL(a,b)  __ASM_FORM(b)
     45 #define _ASM_PTR	__ASM_SEL(.long, .quad)
     46 
     47 	ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE,      _ASM_PTR 0x100000)
     48 	ELFNOTE(Xen, XEN_ELFNOTE_ENTRY,          _ASM_PTR _start)
     49 	ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_ENTRY,   _ASM_PTR _start)    /* entry == virtbase */
     50 	ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET,   _ASM_PTR 0)
     51 
     52        /*
     53 	* Entry point for PVH guests.
     54 	*
     55 	* Xen ABI specifies the following register state when we come here:
     56 	*
     57 	* - `ebx`: contains the physical memory address where the loader has placed
     58 	*          the boot start info structure.
     59 	* - `cr0`: bit 0 (PE) must be set. All the other writable bits are cleared.
     60 	* - `cr4`: all bits are cleared.
     61 	* - `cs `: must be a 32-bit read/execute code segment with a base of ‘0’
     62 	*          and a limit of ‘0xFFFFFFFF’. The selector value is unspecified.
     63 	* - `ds`, `es`: must be a 32-bit read/write data segment with a base of
     64 	*               ‘0’ and a limit of ‘0xFFFFFFFF’. The selector values are all
     65 	*               unspecified.
     66 	* - `tr`: must be a 32-bit TSS (active) with a base of '0' and a limit
     67 	*         of '0x67'.
     68 	* - `eflags`: bit 17 (VM) must be cleared. Bit 9 (IF) must be cleared.
     69 	*             Bit 8 (TF) must be cleared. Other bits are all unspecified.
     70 	*
     71 	* All other processor registers and flag bits are unspecified. The OS is in
     72 	* charge of setting up it's own stack, GDT and IDT.
     73 	*/
     74         .code32
     75         .section .text
     76 
     77 .global _start
     78 _start:
     79 	cld
     80         lgdt gdtr
     81 
     82         ljmp $0x8,$.Lloadcs
     83 .Lloadcs:
     84         mov $0x10,%eax
     85         mov %eax,%ds
     86         mov %eax,%es
     87         mov %eax,%fs
     88         mov %eax,%gs
     89         mov %eax,%ss
     90 
     91 	/* Enable PAE mode (bit 5). */
     92 	mov %cr4, %eax
     93 	btsl $5, %eax
     94 	mov %eax, %cr4
     95 
     96 #define MSR_EFER		0xc0000080 /* extended feature register */
     97 
     98 	/* Enable Long mode. */
     99 	mov $MSR_EFER, %ecx
    100 	rdmsr
    101 	btsl $8, %eax
    102 	wrmsr
    103 
    104 	/* Enable paging */
    105 	mov $.Lpml4, %ecx
    106 	mov %ecx, %cr3
    107 
    108 	mov %cr0, %eax
    109 	btsl $31, %eax
    110 	mov %eax, %cr0
    111 
    112 	/* Jump to 64-bit mode. */
    113         lgdt gdtr64
    114         ljmp $0x8,$.Lenter64
    115 
    116         .code64
    117         .section .text
    118 .Lenter64:
    119 
    120 
    121 	// Setup stack ASAP
    122 	movq $stack_end,%rsp
    123 
    124         /* don't worry about stack frame, assume everthing is garbage when we return */
    125 	call main
    126 
    127 _exit:	/* output any non-zero result in eax to isa-debug-exit device */
    128         test %al, %al
    129         jz 1f
    130         out %ax, $0xf4
    131 
    132 1:      /* QEMU ACPI poweroff */
    133 	mov $0x604,%edx
    134 	mov $0x2000,%eax
    135 	out %ax,%dx
    136 	hlt
    137 	jmp 1b
    138 
    139         /*
    140          * Helper Functions
    141          *
    142          * x86_64 calling convention is rdi, rsi, rdx, rcx, r8, r9
    143          */
    144 
    145         /* Output a single character to serial port */
    146         .global __sys_outc
    147 __sys_outc:
    148         pushq %rax
    149         mov %rax, %rdx
    150 	out %al,$0xE9
    151         popq %rax
    152         ret
    153 
    154 	/* Interrupt Descriptor Table */
    155 
    156         .section .data
    157         .align 16
    158 
    159 idt_00: .int 0, 0
    160 idt_01: .int 0, 0
    161 idt_02: .int 0, 0
    162 idt_03: .int 0, 0
    163 idt_04: .int 0, 0
    164 idt_05: .int 0, 0
    165 idt_06: .int 0, 0 /* intr_6_opcode, Invalid Opcode */
    166 idt_07: .int 0, 0
    167 idt_08: .int 0, 0
    168 idt_09: .int 0, 0
    169 idt_0A: .int 0, 0
    170 idt_0B: .int 0, 0
    171 idt_0C: .int 0, 0
    172 idt_0D: .int 0, 0
    173 idt_0E: .int 0, 0
    174 idt_0F: .int 0, 0
    175 idt_10: .int 0, 0
    176 idt_11: .int 0, 0
    177 idt_12: .int 0, 0
    178 idt_13: .int 0, 0
    179 idt_14: .int 0, 0
    180 idt_15: .int 0, 0
    181 idt_16: .int 0, 0
    182 idt_17: .int 0, 0
    183 idt_18: .int 0, 0
    184 idt_19: .int 0, 0
    185 idt_1A: .int 0, 0
    186 idt_1B: .int 0, 0
    187 idt_1C: .int 0, 0
    188 idt_1D: .int 0, 0
    189 idt_1E: .int 0, 0
    190 idt_1F: .int 0, 0
    191 
    192 
    193 	/*
    194 	 * Global Descriptor Table (GDT)
    195 	 *
    196 	 * This describes various memory areas (segments) through
    197 	 * segment descriptors. In 32 bit mode each segment each
    198 	 * segement is associated with segment registers which are
    199 	 * implicitly (or explicitly) referenced depending on the
    200 	 * instruction. However in 64 bit mode selectors are flat and
    201 	 * segmented addressing isn't used.
    202 	 */
    203 gdt:
    204         .short 0
    205 gdtr:
    206         .short gdt_en - gdt - 1
    207         .int gdt
    208 
    209         // Code cs:
    210         .short 0xFFFF
    211         .short 0
    212         .byte 0
    213         .byte 0x9b
    214         .byte 0xCF
    215         .byte 0
    216 
    217         // Data  ds:, ss:, es:, fs:, and gs:
    218         .short 0xFFFF
    219         .short 0
    220         .byte 0
    221         .byte 0x93
    222         .byte 0xCF
    223         .byte 0
    224 gdt_en:
    225 
    226 gdt64:
    227         .short 0
    228 gdtr64:
    229         .short gdt64_en - gdt64 - 1
    230         .int gdt64
    231 
    232         // Code
    233         .short 0xFFFF
    234         .short 0
    235         .byte 0
    236         .byte 0x9b
    237         .byte 0xAF
    238         .byte 0
    239 
    240         // Data
    241         .short 0xFFFF
    242         .short 0
    243         .byte 0
    244         .byte 0x93
    245         .byte 0xCF
    246         .byte 0
    247 gdt64_en:
    248 
    249 	.section .bss
    250         .align 16
    251 
    252 stack: .space 65536
    253 stack_end:
    254 
    255 	.section .data
    256 
    257 .align 4096
    258 .Lpd:
    259 i = 0
    260         .rept 512 * 4
    261         .quad 0x1e7 | (i << 21)
    262         i = i + 1
    263         .endr
    264 
    265 .align 4096
    266 .Lpdp:
    267         .quad .Lpd + 7 + 0 * 4096 /* 0-1 GB */
    268         .quad .Lpd + 7 + 1 * 4096 /* 1-2 GB */
    269         .quad .Lpd + 7 + 2 * 4096 /* 2-3 GB */
    270         .quad .Lpd + 7 + 3 * 4096 /* 3-4 GB */
    271 
    272 .align 4096
    273 .Lpml4:
    274         .quad .Lpdp + 7 /* 0-512 GB */