[efi] Add EFI image format and basic runtime environment
[people/sha0/gpxe.git] / src / interface / efi / efi_io.c
1 /*
2  * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
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 #include <assert.h>
20 #include <gpxe/io.h>
21 #include <gpxe/efi/efi.h>
22 #include <gpxe/efi/Protocol/CpuIo.h>
23 #include <gpxe/efi/efi_io.h>
24
25 /** @file
26  *
27  * gPXE I/O API for EFI
28  *
29  */
30
31 /** CPU I/O protocol */
32 static EFI_CPU_IO_PROTOCOL *cpu_io;
33 EFI_REQUIRE_PROTOCOL ( EFI_CPU_IO_PROTOCOL, &cpu_io );
34
35 /** Maximum address that can be used for port I/O */
36 #define MAX_PORT_ADDRESS 0xffff
37
38 /**
39  * Determine whether or not address is a port I/O address
40  *
41  * @v io_addr           I/O address
42  * @v is_port           I/O address is a port I/O address
43  */
44 #define IS_PORT_ADDRESS(io_addr) \
45         ( ( ( intptr_t ) (io_addr) ) <= MAX_PORT_ADDRESS )
46
47 /**
48  * Determine EFI CPU I/O width code
49  *
50  * @v size              Size of value
51  * @ret width           EFI width code
52  *
53  * Someone at Intel clearly gets paid by the number of lines of code
54  * they write.  No-one should ever be able to make I/O this
55  * convoluted.  The EFI_CPU_IO_PROTOCOL_WIDTH enum is my favourite
56  * idiocy.
57  */
58 static EFI_CPU_IO_PROTOCOL_WIDTH efi_width ( size_t size ) {
59         switch ( size ) {
60         case 1 :        return EfiCpuIoWidthFifoUint8;
61         case 2 :        return EfiCpuIoWidthFifoUint16;
62         case 4 :        return EfiCpuIoWidthFifoUint32;
63         case 8 :        return EfiCpuIoWidthFifoUint64;
64         default :
65                 assert ( 0 );
66                 /* I wonder what this will actually do... */
67                 return EfiCpuIoWidthMaximum;
68         }
69 }
70
71 /**
72  * Read from device
73  *
74  * @v io_addr           I/O address
75  * @v size              Size of value
76  * @ret data            Value read
77  */
78 unsigned long long efi_ioread ( volatile void *io_addr, size_t size ) {
79         EFI_CPU_IO_PROTOCOL_IO_MEM read;
80         unsigned long long data = 0;
81         EFI_STATUS efirc;
82
83         read = ( IS_PORT_ADDRESS ( io_addr ) ?
84                  cpu_io->Io.Read : cpu_io->Mem.Read );
85
86         if ( ( efirc = read ( cpu_io, efi_width ( size ),
87                               ( intptr_t ) io_addr, 1,
88                               ( void * ) &data ) ) != 0 ) {
89                 DBG ( "EFI I/O read at %p failed: %lx\n", io_addr, efirc );
90                 return -1ULL;
91         }
92
93         return data;
94 }
95
96 /**
97  * Write to device
98  *
99  * @v data              Value to write
100  * @v io_addr           I/O address
101  * @v size              Size of value
102  */
103 void efi_iowrite ( unsigned long long data, volatile void *io_addr,
104                    size_t size ) {
105         EFI_CPU_IO_PROTOCOL_IO_MEM write;
106         EFI_STATUS efirc;
107
108         write = ( IS_PORT_ADDRESS ( io_addr ) ?
109                   cpu_io->Io.Write : cpu_io->Mem.Write );
110
111         if ( ( efirc = write ( cpu_io, efi_width ( size ),
112                                ( intptr_t ) io_addr, 1,
113                                ( void * ) &data ) ) != 0 ) {
114                 DBG ( "EFI I/O write at %p failed: %lx\n", io_addr, efirc );
115         }
116 }
117
118 /**
119  * String read from device
120  *
121  * @v io_addr           I/O address
122  * @v data              Data buffer
123  * @v size              Size of values
124  * @v count             Number of values to read
125  */
126 void efi_ioreads ( volatile void *io_addr, void *data,
127                    size_t size, unsigned int count ) {
128         EFI_CPU_IO_PROTOCOL_IO_MEM read;
129         EFI_STATUS efirc;
130
131         read = ( IS_PORT_ADDRESS ( io_addr ) ?
132                  cpu_io->Io.Read : cpu_io->Mem.Read );
133
134         if ( ( efirc = read ( cpu_io, efi_width ( size ),
135                               ( intptr_t ) io_addr, count,
136                               ( void * ) data ) ) != 0 ) {
137                 DBG ( "EFI I/O string read at %p failed: %lx\n",
138                       io_addr, efirc );
139         }
140 }
141
142 /**
143  * String write to device
144  *
145  * @v io_addr           I/O address
146  * @v data              Data buffer
147  * @v size              Size of values
148  * @v count             Number of values to write
149  */
150 void efi_iowrites ( volatile void *io_addr, const void *data,
151                     size_t size, unsigned int count ) {
152         EFI_CPU_IO_PROTOCOL_IO_MEM write;
153         EFI_STATUS efirc;
154
155         write = ( IS_PORT_ADDRESS ( io_addr ) ?
156                  cpu_io->Io.Write : cpu_io->Mem.Write );
157
158         if ( ( efirc = write ( cpu_io, efi_width ( size ),
159                                ( intptr_t ) io_addr, count,
160                                ( void * ) data ) ) != 0 ) {
161                 DBG ( "EFI I/O write at %p failed: %lx\n",
162                       io_addr, efirc );
163         }
164 }
165
166 /**
167  * Wait for I/O-mapped operation to complete
168  *
169  */
170 static void efi_iodelay ( void ) {
171         /* Write to non-existent port.  Probably x86-only. */
172         outb ( 0, 0x80 );
173 }
174
175 PROVIDE_IOAPI_INLINE ( efi, phys_to_bus );
176 PROVIDE_IOAPI_INLINE ( efi, bus_to_phys );
177 PROVIDE_IOAPI_INLINE ( efi, ioremap );
178 PROVIDE_IOAPI_INLINE ( efi, iounmap );
179 PROVIDE_IOAPI_INLINE ( efi, io_to_bus );
180 PROVIDE_IOAPI_INLINE ( efi, readb );
181 PROVIDE_IOAPI_INLINE ( efi, readw );
182 PROVIDE_IOAPI_INLINE ( efi, readl );
183 PROVIDE_IOAPI_INLINE ( efi, readq );
184 PROVIDE_IOAPI_INLINE ( efi, writeb );
185 PROVIDE_IOAPI_INLINE ( efi, writew );
186 PROVIDE_IOAPI_INLINE ( efi, writel );
187 PROVIDE_IOAPI_INLINE ( efi, writeq );
188 PROVIDE_IOAPI_INLINE ( efi, inb );
189 PROVIDE_IOAPI_INLINE ( efi, inw );
190 PROVIDE_IOAPI_INLINE ( efi, inl );
191 PROVIDE_IOAPI_INLINE ( efi, outb );
192 PROVIDE_IOAPI_INLINE ( efi, outw );
193 PROVIDE_IOAPI_INLINE ( efi, outl );
194 PROVIDE_IOAPI_INLINE ( efi, insb );
195 PROVIDE_IOAPI_INLINE ( efi, insw );
196 PROVIDE_IOAPI_INLINE ( efi, insl );
197 PROVIDE_IOAPI_INLINE ( efi, outsb );
198 PROVIDE_IOAPI_INLINE ( efi, outsw );
199 PROVIDE_IOAPI_INLINE ( efi, outsl );
200 PROVIDE_IOAPI ( efi, iodelay, efi_iodelay );
201 PROVIDE_IOAPI_INLINE ( efi, mb );