| /* |
| * Common Option ROM Functions |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| * |
| * Copyright Novell Inc, 2009 |
| * Authors: Alexander Graf <agraf@suse.de> |
| */ |
| |
| |
| #define FW_CFG_KERNEL_ADDR 0x07 |
| #define FW_CFG_KERNEL_SIZE 0x08 |
| #define FW_CFG_KERNEL_CMDLINE 0x09 |
| #define FW_CFG_INITRD_ADDR 0x0a |
| #define FW_CFG_INITRD_SIZE 0x0b |
| #define FW_CFG_KERNEL_ENTRY 0x10 |
| #define FW_CFG_KERNEL_DATA 0x11 |
| #define FW_CFG_INITRD_DATA 0x12 |
| #define FW_CFG_CMDLINE_ADDR 0x13 |
| #define FW_CFG_CMDLINE_SIZE 0x14 |
| #define FW_CFG_CMDLINE_DATA 0x15 |
| #define FW_CFG_SETUP_ADDR 0x16 |
| #define FW_CFG_SETUP_SIZE 0x17 |
| #define FW_CFG_SETUP_DATA 0x18 |
| |
| #define BIOS_CFG_IOPORT_CFG 0x510 |
| #define BIOS_CFG_IOPORT_DATA 0x511 |
| |
| #define FW_CFG_DMA_CTL_ERROR 0x01 |
| #define FW_CFG_DMA_CTL_READ 0x02 |
| #define FW_CFG_DMA_CTL_SKIP 0x04 |
| #define FW_CFG_DMA_CTL_SELECT 0x08 |
| #define FW_CFG_DMA_CTL_WRITE 0x10 |
| |
| #define FW_CFG_DMA_SIGNATURE 0x51454d5520434647ULL /* "QEMU CFG" */ |
| |
| #define BIOS_CFG_DMA_ADDR_HIGH 0x514 |
| #define BIOS_CFG_DMA_ADDR_LOW 0x518 |
| |
| /* Break the translation block flow so -d cpu shows us values */ |
| #define DEBUG_HERE \ |
| jmp 1f; \ |
| 1: |
| |
| /* |
| * Read a variable from the fw_cfg device. |
| * Clobbers: %edx |
| * Out: %eax |
| */ |
| .macro read_fw VAR |
| mov $\VAR, %ax |
| mov $BIOS_CFG_IOPORT_CFG, %dx |
| outw %ax, (%dx) |
| mov $BIOS_CFG_IOPORT_DATA, %dx |
| inb (%dx), %al |
| shl $8, %eax |
| inb (%dx), %al |
| shl $8, %eax |
| inb (%dx), %al |
| shl $8, %eax |
| inb (%dx), %al |
| bswap %eax |
| .endm |
| |
| |
| /* |
| * Read data from the fw_cfg device using DMA. |
| * Clobbers: %edx, %eax, ADDR, SIZE, memory[%esp-16] to memory[%esp] |
| */ |
| .macro read_fw_dma VAR, SIZE, ADDR |
| /* Address */ |
| bswapl \ADDR |
| pushl \ADDR |
| |
| /* We only support 32 bit target addresses */ |
| xorl %eax, %eax |
| pushl %eax |
| mov $BIOS_CFG_DMA_ADDR_HIGH, %dx |
| outl %eax, (%dx) |
| |
| /* Size */ |
| bswapl \SIZE |
| pushl \SIZE |
| |
| /* Control */ |
| movl $(\VAR << 16) | (FW_CFG_DMA_CTL_READ | FW_CFG_DMA_CTL_SELECT), %eax |
| bswapl %eax |
| pushl %eax |
| |
| movl %esp, %eax /* Address of the struct we generated */ |
| bswapl %eax |
| mov $BIOS_CFG_DMA_ADDR_LOW, %dx |
| outl %eax, (%dx) /* Initiate DMA */ |
| |
| 1: mov (%esp), %eax /* Wait for completion */ |
| bswapl %eax |
| testl $~FW_CFG_DMA_CTL_ERROR, %eax |
| jnz 1b |
| addl $16, %esp |
| .endm |
| |
| |
| /* |
| * Read a blob from the fw_cfg device using DMA |
| * Requires _ADDR, _SIZE and _DATA values for the parameter. |
| * |
| * Clobbers: %eax, %edx, %es, %ecx, %edi and adresses %esp-20 to %esp |
| */ |
| #ifdef USE_FW_CFG_DMA |
| #define read_fw_blob_dma(var) \ |
| read_fw var ## _SIZE; \ |
| mov %eax, %ecx; \ |
| read_fw var ## _ADDR; \ |
| mov %eax, %edi ; \ |
| read_fw_dma var ## _DATA, %ecx, %edi |
| #else |
| #define read_fw_blob_dma(var) read_fw_blob(var) |
| #endif |
| |
| #define read_fw_blob_pre(var) \ |
| read_fw var ## _SIZE; \ |
| mov %eax, %ecx; \ |
| mov $var ## _DATA, %ax; \ |
| mov $BIOS_CFG_IOPORT_CFG, %edx; \ |
| outw %ax, (%dx); \ |
| mov $BIOS_CFG_IOPORT_DATA, %dx; \ |
| cld |
| |
| /* |
| * Read a blob from the fw_cfg device. |
| * Requires _ADDR, _SIZE and _DATA values for the parameter. |
| * |
| * Clobbers: %eax, %edx, %es, %ecx, %edi |
| */ |
| #define read_fw_blob(var) \ |
| read_fw var ## _ADDR; \ |
| mov %eax, %edi; \ |
| read_fw_blob_pre(var); \ |
| /* old as(1) doesn't like this insn so emit the bytes instead: \ |
| rep insb (%dx), %es:(%edi); \ |
| */ \ |
| .dc.b 0xf3,0x6c |
| |
| /* |
| * Read a blob from the fw_cfg device in forced addr32 mode. |
| * Requires _ADDR, _SIZE and _DATA values for the parameter. |
| * |
| * Clobbers: %eax, %edx, %es, %ecx, %edi |
| */ |
| #define read_fw_blob_addr32(var) \ |
| read_fw var ## _ADDR; \ |
| mov %eax, %edi; \ |
| read_fw_blob_pre(var); \ |
| /* old as(1) doesn't like this insn so emit the bytes instead: \ |
| addr32 rep insb (%dx), %es:(%edi); \ |
| */ \ |
| .dc.b 0x67,0xf3,0x6c |
| |
| /* |
| * Read a blob from the fw_cfg device in forced addr32 mode, address is in %edi. |
| * Requires _SIZE and _DATA values for the parameter. |
| * |
| * Clobbers: %eax, %edx, %edi, %es, %ecx |
| */ |
| #define read_fw_blob_addr32_edi(var) \ |
| read_fw_blob_pre(var); \ |
| /* old as(1) doesn't like this insn so emit the bytes instead: \ |
| addr32 rep insb (%dx), %es:(%edi); \ |
| */ \ |
| .dc.b 0x67,0xf3,0x6c |
| |
| #define OPTION_ROM_START \ |
| .code16; \ |
| .text; \ |
| .global _start; \ |
| _start:; \ |
| .short 0xaa55; \ |
| .byte (_end - _start) / 512; |
| |
| #define BOOT_ROM_START \ |
| OPTION_ROM_START \ |
| lret; \ |
| .org 0x18; \ |
| .short 0; \ |
| .short _pnph; \ |
| _pnph: \ |
| .ascii "$PnP"; \ |
| .byte 0x01; \ |
| .byte ( _pnph_len / 16 ); \ |
| .short 0x0000; \ |
| .byte 0x00; \ |
| .byte 0x00; \ |
| .long 0x00000000; \ |
| .short _manufacturer; \ |
| .short _product; \ |
| .long 0x00000000; \ |
| .short 0x0000; \ |
| .short 0x0000; \ |
| .short _bev; \ |
| .short 0x0000; \ |
| .short 0x0000; \ |
| .equ _pnph_len, . - _pnph; \ |
| _bev:; \ |
| /* DS = CS */ \ |
| movw %cs, %ax; \ |
| movw %ax, %ds; |
| |
| #define OPTION_ROM_END \ |
| .byte 0; \ |
| .align 512, 0; \ |
| _end: |
| |
| #define BOOT_ROM_END \ |
| _manufacturer:; \ |
| .asciz "QEMU"; \ |
| _product:; \ |
| .asciz BOOT_ROM_PRODUCT; \ |
| OPTION_ROM_END |
| |