|
|
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.