|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2008 Michael Brown <[email protected]>. ! 3: * ! 4: * This program is free software; you can redistribute it and/or ! 5: * modify it under the terms of the GNU General Public License as ! 6: * published by the Free Software Foundation; either version 2 of the ! 7: * License, or any later version. ! 8: * ! 9: * This program is distributed in the hope that it will be useful, but ! 10: * WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 12: * 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, write to the Free Software ! 16: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 17: */ ! 18: ! 19: FILE_LICENCE ( GPL2_OR_LATER ); ! 20: ! 21: #include <assert.h> ! 22: #include <ipxe/io.h> ! 23: #include <ipxe/efi/efi.h> ! 24: #include <ipxe/efi/Protocol/CpuIo.h> ! 25: #include <ipxe/efi/efi_io.h> ! 26: ! 27: /** @file ! 28: * ! 29: * iPXE I/O API for EFI ! 30: * ! 31: */ ! 32: ! 33: /** CPU I/O protocol */ ! 34: static EFI_CPU_IO_PROTOCOL *cpu_io; ! 35: EFI_REQUIRE_PROTOCOL ( EFI_CPU_IO_PROTOCOL, &cpu_io ); ! 36: ! 37: /** Maximum address that can be used for port I/O */ ! 38: #define MAX_PORT_ADDRESS 0xffff ! 39: ! 40: /** ! 41: * Determine whether or not address is a port I/O address ! 42: * ! 43: * @v io_addr I/O address ! 44: * @v is_port I/O address is a port I/O address ! 45: */ ! 46: #define IS_PORT_ADDRESS(io_addr) \ ! 47: ( ( ( intptr_t ) (io_addr) ) <= MAX_PORT_ADDRESS ) ! 48: ! 49: /** ! 50: * Determine EFI CPU I/O width code ! 51: * ! 52: * @v size Size of value ! 53: * @ret width EFI width code ! 54: * ! 55: * Someone at Intel clearly gets paid by the number of lines of code ! 56: * they write. No-one should ever be able to make I/O this ! 57: * convoluted. The EFI_CPU_IO_PROTOCOL_WIDTH enum is my favourite ! 58: * idiocy. ! 59: */ ! 60: static EFI_CPU_IO_PROTOCOL_WIDTH efi_width ( size_t size ) { ! 61: switch ( size ) { ! 62: case 1 : return EfiCpuIoWidthFifoUint8; ! 63: case 2 : return EfiCpuIoWidthFifoUint16; ! 64: case 4 : return EfiCpuIoWidthFifoUint32; ! 65: case 8 : return EfiCpuIoWidthFifoUint64; ! 66: default : ! 67: assert ( 0 ); ! 68: /* I wonder what this will actually do... */ ! 69: return EfiCpuIoWidthMaximum; ! 70: } ! 71: } ! 72: ! 73: /** ! 74: * Read from device ! 75: * ! 76: * @v io_addr I/O address ! 77: * @v size Size of value ! 78: * @ret data Value read ! 79: */ ! 80: unsigned long long efi_ioread ( volatile void *io_addr, size_t size ) { ! 81: EFI_CPU_IO_PROTOCOL_IO_MEM read; ! 82: unsigned long long data = 0; ! 83: EFI_STATUS efirc; ! 84: ! 85: read = ( IS_PORT_ADDRESS ( io_addr ) ? ! 86: cpu_io->Io.Read : cpu_io->Mem.Read ); ! 87: ! 88: if ( ( efirc = read ( cpu_io, efi_width ( size ), ! 89: ( intptr_t ) io_addr, 1, ! 90: ( void * ) &data ) ) != 0 ) { ! 91: DBG ( "EFI I/O read at %p failed: %s\n", ! 92: io_addr, efi_strerror ( efirc ) ); ! 93: return -1ULL; ! 94: } ! 95: ! 96: return data; ! 97: } ! 98: ! 99: /** ! 100: * Write to device ! 101: * ! 102: * @v data Value to write ! 103: * @v io_addr I/O address ! 104: * @v size Size of value ! 105: */ ! 106: void efi_iowrite ( unsigned long long data, volatile void *io_addr, ! 107: size_t size ) { ! 108: EFI_CPU_IO_PROTOCOL_IO_MEM write; ! 109: EFI_STATUS efirc; ! 110: ! 111: write = ( IS_PORT_ADDRESS ( io_addr ) ? ! 112: cpu_io->Io.Write : cpu_io->Mem.Write ); ! 113: ! 114: if ( ( efirc = write ( cpu_io, efi_width ( size ), ! 115: ( intptr_t ) io_addr, 1, ! 116: ( void * ) &data ) ) != 0 ) { ! 117: DBG ( "EFI I/O write at %p failed: %s\n", ! 118: io_addr, efi_strerror ( efirc ) ); ! 119: } ! 120: } ! 121: ! 122: /** ! 123: * String read from device ! 124: * ! 125: * @v io_addr I/O address ! 126: * @v data Data buffer ! 127: * @v size Size of values ! 128: * @v count Number of values to read ! 129: */ ! 130: void efi_ioreads ( volatile void *io_addr, void *data, ! 131: size_t size, unsigned int count ) { ! 132: EFI_CPU_IO_PROTOCOL_IO_MEM read; ! 133: EFI_STATUS efirc; ! 134: ! 135: read = ( IS_PORT_ADDRESS ( io_addr ) ? ! 136: cpu_io->Io.Read : cpu_io->Mem.Read ); ! 137: ! 138: if ( ( efirc = read ( cpu_io, efi_width ( size ), ! 139: ( intptr_t ) io_addr, count, ! 140: ( void * ) data ) ) != 0 ) { ! 141: DBG ( "EFI I/O string read at %p failed: %s\n", ! 142: io_addr, efi_strerror ( efirc ) ); ! 143: } ! 144: } ! 145: ! 146: /** ! 147: * String write to device ! 148: * ! 149: * @v io_addr I/O address ! 150: * @v data Data buffer ! 151: * @v size Size of values ! 152: * @v count Number of values to write ! 153: */ ! 154: void efi_iowrites ( volatile void *io_addr, const void *data, ! 155: size_t size, unsigned int count ) { ! 156: EFI_CPU_IO_PROTOCOL_IO_MEM write; ! 157: EFI_STATUS efirc; ! 158: ! 159: write = ( IS_PORT_ADDRESS ( io_addr ) ? ! 160: cpu_io->Io.Write : cpu_io->Mem.Write ); ! 161: ! 162: if ( ( efirc = write ( cpu_io, efi_width ( size ), ! 163: ( intptr_t ) io_addr, count, ! 164: ( void * ) data ) ) != 0 ) { ! 165: DBG ( "EFI I/O write at %p failed: %s\n", ! 166: io_addr, efi_strerror ( efirc ) ); ! 167: } ! 168: } ! 169: ! 170: /** ! 171: * Wait for I/O-mapped operation to complete ! 172: * ! 173: */ ! 174: static void efi_iodelay ( void ) { ! 175: /* Write to non-existent port. Probably x86-only. */ ! 176: outb ( 0, 0x80 ); ! 177: } ! 178: ! 179: /** ! 180: * Get memory map ! 181: * ! 182: * Can't be done on EFI so return an empty map ! 183: * ! 184: * @v memmap Memory map to fill in ! 185: */ ! 186: static void efi_get_memmap ( struct memory_map *memmap ) { ! 187: memmap->count = 0; ! 188: } ! 189: ! 190: PROVIDE_IOAPI_INLINE ( efi, phys_to_bus ); ! 191: PROVIDE_IOAPI_INLINE ( efi, bus_to_phys ); ! 192: PROVIDE_IOAPI_INLINE ( efi, ioremap ); ! 193: PROVIDE_IOAPI_INLINE ( efi, iounmap ); ! 194: PROVIDE_IOAPI_INLINE ( efi, io_to_bus ); ! 195: PROVIDE_IOAPI_INLINE ( efi, readb ); ! 196: PROVIDE_IOAPI_INLINE ( efi, readw ); ! 197: PROVIDE_IOAPI_INLINE ( efi, readl ); ! 198: PROVIDE_IOAPI_INLINE ( efi, readq ); ! 199: PROVIDE_IOAPI_INLINE ( efi, writeb ); ! 200: PROVIDE_IOAPI_INLINE ( efi, writew ); ! 201: PROVIDE_IOAPI_INLINE ( efi, writel ); ! 202: PROVIDE_IOAPI_INLINE ( efi, writeq ); ! 203: PROVIDE_IOAPI_INLINE ( efi, inb ); ! 204: PROVIDE_IOAPI_INLINE ( efi, inw ); ! 205: PROVIDE_IOAPI_INLINE ( efi, inl ); ! 206: PROVIDE_IOAPI_INLINE ( efi, outb ); ! 207: PROVIDE_IOAPI_INLINE ( efi, outw ); ! 208: PROVIDE_IOAPI_INLINE ( efi, outl ); ! 209: PROVIDE_IOAPI_INLINE ( efi, insb ); ! 210: PROVIDE_IOAPI_INLINE ( efi, insw ); ! 211: PROVIDE_IOAPI_INLINE ( efi, insl ); ! 212: PROVIDE_IOAPI_INLINE ( efi, outsb ); ! 213: PROVIDE_IOAPI_INLINE ( efi, outsw ); ! 214: PROVIDE_IOAPI_INLINE ( efi, outsl ); ! 215: PROVIDE_IOAPI ( efi, iodelay, efi_iodelay ); ! 216: PROVIDE_IOAPI_INLINE ( efi, mb ); ! 217: PROVIDE_IOAPI ( efi, get_memmap, efi_get_memmap );
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.