/* * 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 . * * Copyright Novell Inc, 2009 * Authors: Alexander Graf */ #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