qemu/pc-bios/optionrom/pvh.S
<<
>>
Prefs
   1/*
   2 * PVH Option ROM
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License as published by
   6 * the Free Software Foundation; either version 2 of the License, or
   7 * (at your option) any later version.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
  16 *
  17 * Copyright Novell Inc, 2009
  18 *   Authors: Alexander Graf <agraf@suse.de>
  19 *
  20 * Copyright (c) 2019 Red Hat Inc.
  21 *   Authors: Stefano Garzarella <sgarzare@redhat.com>
  22 */
  23
  24#include "optionrom.h"
  25
  26#define BOOT_ROM_PRODUCT "PVH loader"
  27
  28#define GS_PROT_JUMP            0
  29#define GS_GDT_DESC             6
  30
  31#ifdef OPTION_ROM_START
  32#undef OPTION_ROM_START
  33#endif
  34#ifdef OPTION_ROM_END
  35#undef OPTION_ROM_END
  36#endif
  37
  38/*
  39 * Redefine OPTION_ROM_START and OPTION_ROM_END, because this rom is produced
  40 * linking multiple objects.
  41 * signrom.py will add padding.
  42 */
  43#define OPTION_ROM_START                                \
  44    .code16;                                            \
  45    .text;                                              \
  46        .global         _start;                         \
  47    _start:;                                            \
  48        .short          0xaa55;                         \
  49        .byte           3; /* desired size in 512 units */
  50
  51#define OPTION_ROM_END                                  \
  52    _end:
  53
  54BOOT_ROM_START
  55
  56run_pvhboot:
  57
  58        cli
  59        cld
  60
  61        mov             %cs, %eax
  62        shl             $0x4, %eax
  63
  64        /* set up a long jump descriptor that is PC relative */
  65
  66        /* move stack memory to %gs */
  67        mov             %ss, %ecx
  68        shl             $0x4, %ecx
  69        mov             %esp, %ebx
  70        add             %ebx, %ecx
  71        sub             $0x20, %ecx
  72        sub             $0x30, %esp
  73        shr             $0x4, %ecx
  74        mov             %cx, %gs
  75
  76        /* now push the indirect jump descriptor there */
  77        mov             (prot_jump), %ebx
  78        add             %eax, %ebx
  79        movl            %ebx, %gs:GS_PROT_JUMP
  80        mov             $8, %bx
  81        movw            %bx, %gs:GS_PROT_JUMP + 4
  82
  83        /* fix the gdt descriptor to be PC relative */
  84        movw            (gdt_desc), %bx
  85        movw            %bx, %gs:GS_GDT_DESC
  86        movl            (gdt_desc+2), %ebx
  87        add             %eax, %ebx
  88        movl            %ebx, %gs:GS_GDT_DESC + 2
  89
  90        /* initialize HVM memmap table using int 0x15(e820) */
  91
  92        /* ES = pvh_e820 struct */
  93        mov             $pvh_e820, %eax
  94        shr             $4, %eax
  95        mov             %ax, %es
  96
  97        /* start storing memmap table at %es:8 (pvh_e820.table) */
  98        mov             $8,%edi
  99        xor             %ebx, %ebx
 100        jmp             memmap_loop
 101
 102memmap_loop_check:
 103        /* pvh_e820 can contains up to 128 entries */
 104        cmp             $128, %ebx
 105        je              memmap_done
 106
 107memmap_loop:
 108        /* entry size (hvm_memmap_table_entry) & max buffer size (int15) */
 109        movl            $24, %ecx
 110        /* e820 */
 111        movl            $0x0000e820, %eax
 112        /* 'SMAP' magic */
 113        movl            $0x534d4150, %edx
 114        /* store counter value at %es:0 (pvh_e820.entries) */
 115        movl            %ebx, %es:0
 116
 117        int             $0x15
 118        /* error or last entry already done? */
 119        jb              memmap_err
 120
 121        /* %edi += entry size (hvm_memmap_table_entry) */
 122        add             $24, %edi
 123
 124        /* continuation value 0 means last entry */
 125        test            %ebx, %ebx
 126        jnz             memmap_loop_check
 127
 128        /* increase pvh_e820.entries to save the last entry */
 129        movl            %es:0, %ebx
 130        inc             %ebx
 131
 132memmap_done:
 133        movl            %ebx, %es:0
 134
 135memmap_err:
 136
 137        /* load the GDT before going into protected mode */
 138lgdt:
 139        data32 lgdt     %gs:GS_GDT_DESC
 140
 141        /* get us to protected mode now */
 142        movl            $1, %eax
 143        movl            %eax, %cr0
 144
 145        /* the LJMP sets CS for us and gets us to 32-bit */
 146ljmp:
 147        data32 ljmp     *%gs:GS_PROT_JUMP
 148
 149prot_mode:
 150.code32
 151
 152        /* initialize all other segments */
 153        movl            $0x10, %eax
 154        movl            %eax, %ss
 155        movl            %eax, %ds
 156        movl            %eax, %es
 157        movl            %eax, %fs
 158        movl            %eax, %gs
 159
 160        jmp pvh_load_kernel
 161
 162/* Variables */
 163.align 4, 0
 164prot_jump:      .long prot_mode
 165                .short 8
 166
 167.align 4, 0
 168gdt:
 169        /* 0x00 */
 170.byte   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 171
 172        /*
 173         * 0x08: code segment
 174         * (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k)
 175         */
 176.byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00
 177
 178        /*
 179         * 0x10: data segment
 180         * (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k)
 181         */
 182.byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00
 183
 184        /*
 185         * 0x18: code segment
 186         * (base=0, limit=0x0ffff, type=16bit code exec/read/conf, DPL=0, 1b)
 187         */
 188.byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00
 189
 190        /*
 191         * 0x20: data segment
 192         * (base=0, limit=0x0ffff, type=16bit data read/write, DPL=0, 1b)
 193         */
 194.byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00
 195
 196gdt_desc:
 197.short  (5 * 8) - 1
 198.long   gdt
 199
 200BOOT_ROM_END
 201