iPXE
int13con.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 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 (at your option) 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., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 #include <stdint.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <ipxe/console.h>
30 #include <ipxe/init.h>
31 #include <realmode.h>
32 #include <int13.h>
33 #include <config/console.h>
34 
35 /** @file
36  *
37  * INT13 disk log console
38  *
39  */
40 
41 /* Set default console usage if applicable */
42 #if ! ( defined ( CONSOLE_INT13 ) && CONSOLE_EXPLICIT ( CONSOLE_INT13 ) )
43 #undef CONSOLE_INT13
44 #define CONSOLE_INT13 ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
45 #endif
46 
47 /** Disk drive number */
48 #define INT13CON_DRIVE 0x80
49 
50 /** Log partition type */
51 #define INT13CON_PARTITION_TYPE 0xe0
52 
53 /** Maximum number of outstanding unwritten characters */
54 #define INT13CON_MAX_UNWRITTEN 64
55 
56 /** Log partition header */
58  /** Magic signature */
59  char magic[10];
60 } __attribute__ (( packed ));
61 
62 /** Log partition magic signature */
63 #define INT13CON_MAGIC "iPXE LOG\n\n"
64 
65 /** Original INT13 vector */
66 static struct segoff __bss16 ( int13con_vector );
67 #define int13con_vector __use_data16 ( int13con_vector )
68 
69 /** Sector buffer */
71 #define int13con_buffer __use_data16 ( int13con_buffer )
72 
73 /** Disk address packet */
75 #define int13con_address __use_data16 ( int13con_address )
76 
77 /** Current LBA */
79 
80 /** Maximum LBA */
82 
83 /** Current offset within sector */
84 static size_t int13con_offset;
85 
86 /** Number of unwritten characters */
87 static size_t int13con_unwritten;
88 
90 
91 /**
92  * Read/write disk sector
93  *
94  * @v op Operation
95  * @v lba Logical block address
96  * @ret rc Return status code
97  */
98 static int int13con_rw ( unsigned int op, uint64_t lba ) {
99  uint8_t error;
100 
101  /* Construct disk address packet */
102  int13con_address.bufsize = sizeof ( int13con_address );
103  int13con_address.count = 1;
104  int13con_address.buffer.segment = rm_ds;
105  int13con_address.buffer.offset = __from_data16 ( int13con_buffer );
106  int13con_address.lba = lba;
107 
108  /* Emulate INT13 via original vector. We do this since iPXE
109  * (or another subsequent bootloader) may hook INT13 and remap
110  * drive numbers.
111  */
112  __asm__ ( REAL_CODE ( "pushfw\n\t"
113  "cli\n\t"
114  "lcall *int13con_vector\n\t" )
115  : "=a" ( error )
116  : "0" ( op << 8 ), "d" ( INT13CON_DRIVE ),
117  "S" ( __from_data16 ( &int13con_address ) ) );
118  if ( error ) {
119  DBG ( "INT13CON operation %04x failed: %02x\n",
120  op, error );
121  return -EIO;
122  }
123 
124  return 0;
125 }
126 
127 /**
128  * Write character to console
129  *
130  * @v character Character
131  */
132 static void int13con_putchar ( int character ) {
133  static int busy;
134  int rc;
135 
136  /* Ignore if we are already mid-logging */
137  if ( busy )
138  return;
139  busy = 1;
140 
141  /* Write character to buffer */
142  int13con_buffer[int13con_offset++] = character;
144 
145  /* Write sector to disk, if applicable */
146  if ( ( int13con_offset == INT13_BLKSIZE ) ||
148  ( character == '\n' ) ) {
149 
150  /* Write sector to disk */
152  int13con_lba ) ) != 0 ) {
153  DBG ( "INT13CON could not write log\n" );
154  /* Ignore and continue; there's nothing we can do */
155  }
156 
157  /* Reset count of unwritten characters */
158  int13con_unwritten = 0;
159  }
160 
161  /* Move to next sector, if applicable */
162  if ( int13con_offset == INT13_BLKSIZE ) {
163 
164  /* Disable console if we have run out of space */
166  int13con.disabled = 1;
167 
168  /* Clear log buffer */
169  memset ( int13con_buffer, 0, sizeof ( int13con_buffer ) );
170  int13con_offset = 0;
171 
172  /* Move to next sector */
173  int13con_lba++;
174  }
175 
176  /* Clear busy flag */
177  busy = 0;
178 }
179 
180 /**
181  * Find log partition
182  *
183  * @ret rc Return status code
184  */
185 static int int13con_find ( void ) {
186  struct master_boot_record *mbr =
187  ( ( struct master_boot_record * ) int13con_buffer );
188  struct int13con_header *hdr =
189  ( ( struct int13con_header * ) int13con_buffer );
190  struct partition_table_entry part[4];
191  unsigned int i;
192  int rc;
193 
194  /* Read MBR */
195  if ( ( rc = int13con_rw ( INT13_EXTENDED_READ, 0 ) ) != 0 ) {
196  DBG ( "INT13CON could not read MBR: %s\n", strerror ( rc ) );
197  return rc;
198  }
199 
200  /* Check MBR magic */
201  if ( mbr->magic != INT13_MBR_MAGIC ) {
202  DBG ( "INT13CON incorrect MBR magic\n" );
203  DBG2_HDA ( 0, mbr, sizeof ( *mbr ) );
204  return -EINVAL;
205  }
206 
207  /* Look for magic partition */
208  memcpy ( part, mbr->partitions, sizeof ( part ) );
209  for ( i = 0 ; i < ( sizeof ( part ) / sizeof ( part[0] ) ) ; i++ ) {
210 
211  /* Skip partitions of the wrong type */
212  if ( part[i].type != INT13CON_PARTITION_TYPE )
213  continue;
214 
215  /* Read partition header */
217  part[i].start ) ) != 0 ) {
218  DBG ( "INT13CON partition %d could not read header: "
219  "%s\n", ( i + 1 ), strerror ( rc ) );
220  continue;
221  }
222 
223  /* Check partition header */
224  if ( memcmp ( hdr->magic, INT13CON_MAGIC,
225  sizeof ( hdr->magic ) ) != 0 ) {
226  DBG ( "INT13CON partition %d bad magic\n", ( i + 1 ) );
227  DBG2_HDA ( 0, hdr, sizeof ( *hdr ) );
228  continue;
229  }
230 
231  /* Found log partition */
232  DBG ( "INT13CON partition %d at [%08x,%08x)\n", ( i + 1 ),
233  part[i].start, ( part[i].start + part[i].length ) );
234  int13con_lba = part[i].start;
235  int13con_max_lba = ( part[i].start + part[i].length - 1 );
236 
237  /* Initialise log buffer */
238  memset ( &int13con_buffer[ sizeof ( *hdr ) ], 0,
239  ( sizeof ( int13con_buffer ) - sizeof ( *hdr ) ) );
240  int13con_offset = sizeof ( hdr->magic );
241 
242  return 0;
243  }
244 
245  DBG ( "INT13CON found no log partition\n" );
246  return -ENOENT;
247 }
248 
249 /**
250  * Initialise INT13 console
251  *
252  */
253 static void int13con_init ( void ) {
254  uint8_t error;
255  uint16_t check;
256  unsigned int discard_c;
257  unsigned int discard_d;
258  int rc;
259 
260  /* Check for INT13 extensions */
261  __asm__ __volatile__ ( REAL_CODE ( "int $0x13\n\t"
262  "setc %%al\n\t" )
263  : "=a" ( error ), "=b" ( check ),
264  "=c" ( discard_c ), "=d" ( discard_d )
265  : "0" ( INT13_EXTENSION_CHECK << 8 ),
266  "1" ( 0x55aa ), "3" ( INT13CON_DRIVE ) );
267  if ( error || ( check != 0xaa55 ) ) {
268  DBG ( "INT13CON missing extensions (%02x,%04x)\n",
269  error, check );
270  return;
271  }
272 
273  /* Store original INT13 vector */
274  copy_from_real ( &int13con_vector, 0, ( 0x13 * 4 ),
275  sizeof ( int13con_vector ) );
276  DBG ( "INT13CON using original INT13 vector %04x:%04x\n",
277  int13con_vector.segment, int13con_vector.offset );
278 
279  /* Locate log partition */
280  if ( ( rc = int13con_find() ) != 0)
281  return;
282 
283  /* Enable console */
284  int13con.disabled = 0;
285 }
286 
287 /**
288  * INT13 console initialisation function
289  */
290 struct init_fn int13con_init_fn __init_fn ( INIT_CONSOLE ) = {
292 };
293 
294 /** INT13 console driver */
295 struct console_driver int13con __console_driver = {
297  .disabled = CONSOLE_DISABLED,
298  .usage = CONSOLE_INT13,
299 };
#define __attribute__(x)
Definition: compiler.h:10
uint16_t length
Length.
Definition: intel.h:14
#define EINVAL
Invalid argument.
Definition: errno.h:428
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
unsigned short uint16_t
Definition: stdint.h:11
struct init_fn int13con_init_fn __init_fn(INIT_CONSOLE)
INT13 console initialisation function.
#define INT13_MBR_MAGIC
MBR magic signature.
Definition: int13.h:292
struct partition_table_entry partitions[4]
Partition table.
Definition: int13.h:286
void(* initialise)(void)
Definition: init.h:15
uint32_t lba
Start address.
Definition: scsi.h:23
static uint64_t int13con_max_lba
Maximum LBA.
Definition: int13con.c:81
static void int13con_putchar(int character)
Write character to console.
Definition: int13con.c:132
#define INT13_EXTENSION_CHECK
Extensions installation check.
Definition: int13.h:35
#define INT13CON_DRIVE
Disk drive number.
Definition: int13con.c:48
#define INT13CON_MAX_UNWRITTEN
Maximum number of outstanding unwritten characters.
Definition: int13con.c:54
Error codes.
#define INT13_EXTENDED_WRITE
Extended write.
Definition: int13.h:39
uint32_t start
Linear start address.
Definition: int13.h:272
static uint64_t int13con_lba
Current LBA.
Definition: int13con.c:78
struct console_driver int13con __console_driver
INT13 console driver.
Definition: int13con.c:89
uint8_t type
Type.
Definition: ena.h:16
#define CONSOLE_DISABLED
Console is disabled for all uses.
Definition: console.h:111
An INT 13 disk address packet.
Definition: int13.h:88
struct arbelprm_completion_with_error error
Definition: arbel.h:12
static size_t int13con_unwritten
Number of unwritten characters.
Definition: int13con.c:87
static uint8_t __bss16_array(int13con_buffer, [INT13_BLKSIZE])
Sector buffer.
#define ENOENT
No such file or directory.
Definition: errno.h:514
unsigned long long uint64_t
Definition: stdint.h:13
#define rm_ds
Definition: libkir.h:39
#define int13con_address
Definition: int13con.c:75
#define INT13_BLKSIZE
Block size for non-extended INT 13 calls.
Definition: int13.h:72
static size_t int13con_offset
Current offset within sector.
Definition: int13con.c:84
static struct segoff __bss16(int13con_vector)
Original INT13 vector.
uint32_t start
Starting offset.
Definition: netvsc.h:12
void * memcpy(void *dest, const void *src, size_t len) __nonnull
An initialisation function.
Definition: init.h:14
void(* putchar)(int character)
Write a character to the console.
Definition: console.h:68
char magic[10]
Magic signature.
Definition: int13con.c:59
#define int13con_vector
Definition: int13con.c:67
INT 13 emulation.
#define INT13CON_MAGIC
Log partition magic signature.
Definition: int13con.c:63
A Master Boot Record.
Definition: int13.h:278
User interaction.
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
static void int13con_init(void)
Initialise INT13 console.
Definition: int13con.c:253
#define DBG2_HDA(...)
Definition: compiler.h:516
uint32_t length
Linear length.
Definition: int13.h:274
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
unsigned char uint8_t
Definition: stdint.h:10
Console configuration.
#define CONSOLE_INT13
Definition: int13con.c:44
__asm__ __volatile__("\n1:\n\t" "movb -1(%2,%1), %%al\n\t" "stosb\n\t" "loop 1b\n\t" "xorl %%eax, %%eax\n\t" "mov %3, %1\n\t" "rep stosb\n\t" :"=&D"(discard_D), "=&c"(discard_c) :"r"(data), "g"(pad_len), "0"(value0), "1"(len) :"eax")
#define INIT_CONSOLE
Console initialisation.
Definition: init.h:29
uint32_t hdr
Message header.
Definition: intelvf.h:12
#define copy_from_real
Definition: libkir.h:79
static uint16_t struct vmbus_xfer_pages_operations * op
Definition: netvsc.h:327
__asm__(".section \".rodata\", \"a\", " PROGBITS "\n\t" "\nprivate_key_data:\n\t" ".size private_key_data, ( . - private_key_data )\n\t" ".equ private_key_len, ( . - private_key_data )\n\t" ".previous\n\t")
static int int13con_rw(unsigned int op, uint64_t lba)
Read/write disk sector.
Definition: int13con.c:98
#define __from_data16(pointer)
Definition: libkir.h:22
#define EIO
Input/output error.
Definition: errno.h:433
#define int13con_buffer
Definition: int13con.c:71
#define INT13CON_PARTITION_TYPE
Log partition type.
Definition: int13con.c:51
long discard_c
Definition: bigint.h:30
A console driver.
Definition: console.h:55
#define INT13_EXTENDED_READ
Extended read.
Definition: int13.h:37
Log partition header.
Definition: int13con.c:57
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
A partition table entry within the MBR.
Definition: int13.h:262
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:98
#define REAL_CODE(asm_code_str)
Definition: libkir.h:226
String functions.
uint16_t magic
0x55aa MBR signature
Definition: int13.h:288
void * memset(void *dest, int character, size_t len) __nonnull
static int int13con_find(void)
Find log partition.
Definition: int13con.c:185