You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

int13con.c 7.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  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. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. #include <stdint.h>
  25. #include <string.h>
  26. #include <errno.h>
  27. #include <ipxe/console.h>
  28. #include <ipxe/init.h>
  29. #include <realmode.h>
  30. #include <int13.h>
  31. #include <config/console.h>
  32. /** @file
  33. *
  34. * INT13 disk log console
  35. *
  36. */
  37. /* Set default console usage if applicable */
  38. #if ! ( defined ( CONSOLE_INT13 ) && CONSOLE_EXPLICIT ( CONSOLE_INT13 ) )
  39. #undef CONSOLE_INT13
  40. #define CONSOLE_INT13 ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
  41. #endif
  42. /** Disk drive number */
  43. #define INT13CON_DRIVE 0x80
  44. /** Log partition type */
  45. #define INT13CON_PARTITION_TYPE 0xe0
  46. /** Maximum number of outstanding unwritten characters */
  47. #define INT13CON_MAX_UNWRITTEN 64
  48. /** Log partition header */
  49. struct int13con_header {
  50. /** Magic signature */
  51. char magic[10];
  52. } __attribute__ (( packed ));
  53. /** Log partition magic signature */
  54. #define INT13CON_MAGIC "iPXE LOG\n\n"
  55. /** Original INT13 vector */
  56. static struct segoff __bss16 ( int13con_vector );
  57. #define int13con_vector __use_data16 ( int13con_vector )
  58. /** Sector buffer */
  59. static uint8_t __bss16_array ( int13con_buffer, [INT13_BLKSIZE] );
  60. #define int13con_buffer __use_data16 ( int13con_buffer )
  61. /** Disk address packet */
  62. static struct int13_disk_address __bss16 ( int13con_address );
  63. #define int13con_address __use_data16 ( int13con_address )
  64. /** Current LBA */
  65. static uint64_t int13con_lba;
  66. /** Maximum LBA */
  67. static uint64_t int13con_max_lba;
  68. /** Current offset within sector */
  69. static size_t int13con_offset;
  70. /** Number of unwritten characters */
  71. static size_t int13con_unwritten;
  72. struct console_driver int13con __console_driver;
  73. /**
  74. * Read/write disk sector
  75. *
  76. * @v op Operation
  77. * @v lba Logical block address
  78. * @ret rc Return status code
  79. */
  80. static int int13con_rw ( unsigned int op, uint64_t lba ) {
  81. uint8_t error;
  82. /* Construct disk address packet */
  83. int13con_address.bufsize = sizeof ( int13con_address );
  84. int13con_address.count = 1;
  85. int13con_address.buffer.segment = rm_ds;
  86. int13con_address.buffer.offset = __from_data16 ( int13con_buffer );
  87. int13con_address.lba = lba;
  88. /* Emulate INT13 via original vector. We do this since iPXE
  89. * (or another subsequent bootloader) may hook INT13 and remap
  90. * drive numbers.
  91. */
  92. __asm__ ( REAL_CODE ( "pushfw\n\t"
  93. "cli\n\t"
  94. "lcall *int13con_vector\n\t" )
  95. : "=a" ( error )
  96. : "0" ( op << 8 ), "d" ( INT13CON_DRIVE ),
  97. "S" ( __from_data16 ( &int13con_address ) ) );
  98. if ( error ) {
  99. DBG ( "INT13CON operation %04x failed: %02x\n",
  100. op, error );
  101. return -EIO;
  102. }
  103. return 0;
  104. }
  105. /**
  106. * Write character to console
  107. *
  108. * @v character Character
  109. */
  110. static void int13con_putchar ( int character ) {
  111. static int busy;
  112. int rc;
  113. /* Ignore if we are already mid-logging */
  114. if ( busy )
  115. return;
  116. busy = 1;
  117. /* Write character to buffer */
  118. int13con_buffer[int13con_offset++] = character;
  119. int13con_unwritten++;
  120. /* Write sector to disk, if applicable */
  121. if ( ( int13con_offset == INT13_BLKSIZE ) ||
  122. ( int13con_unwritten == INT13CON_MAX_UNWRITTEN ) ||
  123. ( character == '\n' ) ) {
  124. /* Write sector to disk */
  125. if ( ( rc = int13con_rw ( INT13_EXTENDED_WRITE,
  126. int13con_lba ) ) != 0 ) {
  127. DBG ( "INT13CON could not write log\n" );
  128. /* Ignore and continue; there's nothing we can do */
  129. }
  130. /* Reset count of unwritten characters */
  131. int13con_unwritten = 0;
  132. }
  133. /* Move to next sector, if applicable */
  134. if ( int13con_offset == INT13_BLKSIZE ) {
  135. /* Disable console if we have run out of space */
  136. if ( int13con_lba >= int13con_max_lba )
  137. int13con.disabled = 1;
  138. /* Clear log buffer */
  139. memset ( int13con_buffer, 0, sizeof ( int13con_buffer ) );
  140. int13con_offset = 0;
  141. /* Move to next sector */
  142. int13con_lba++;
  143. }
  144. /* Clear busy flag */
  145. busy = 0;
  146. }
  147. /**
  148. * Find log partition
  149. *
  150. * @ret rc Return status code
  151. */
  152. static int int13con_find ( void ) {
  153. struct master_boot_record *mbr =
  154. ( ( struct master_boot_record * ) int13con_buffer );
  155. struct int13con_header *hdr =
  156. ( ( struct int13con_header * ) int13con_buffer );
  157. struct partition_table_entry part[4];
  158. unsigned int i;
  159. int rc;
  160. /* Read MBR */
  161. if ( ( rc = int13con_rw ( INT13_EXTENDED_READ, 0 ) ) != 0 ) {
  162. DBG ( "INT13CON could not read MBR: %s\n", strerror ( rc ) );
  163. return rc;
  164. }
  165. /* Check MBR magic */
  166. if ( mbr->magic != INT13_MBR_MAGIC ) {
  167. DBG ( "INT13CON incorrect MBR magic\n" );
  168. DBG2_HDA ( 0, mbr, sizeof ( *mbr ) );
  169. return -EINVAL;
  170. }
  171. /* Look for magic partition */
  172. memcpy ( part, mbr->partitions, sizeof ( part ) );
  173. for ( i = 0 ; i < ( sizeof ( part ) / sizeof ( part[0] ) ) ; i++ ) {
  174. /* Skip partitions of the wrong type */
  175. if ( part[i].type != INT13CON_PARTITION_TYPE )
  176. continue;
  177. /* Read partition header */
  178. if ( ( rc = int13con_rw ( INT13_EXTENDED_READ,
  179. part[i].start ) ) != 0 ) {
  180. DBG ( "INT13CON partition %d could not read header: "
  181. "%s\n", ( i + 1 ), strerror ( rc ) );
  182. continue;
  183. }
  184. /* Check partition header */
  185. if ( memcmp ( hdr->magic, INT13CON_MAGIC,
  186. sizeof ( hdr->magic ) ) != 0 ) {
  187. DBG ( "INT13CON partition %d bad magic\n", ( i + 1 ) );
  188. DBG2_HDA ( 0, hdr, sizeof ( *hdr ) );
  189. continue;
  190. }
  191. /* Found log partition */
  192. DBG ( "INT13CON partition %d at [%08x,%08x)\n", ( i + 1 ),
  193. part[i].start, ( part[i].start + part[i].length ) );
  194. int13con_lba = part[i].start;
  195. int13con_max_lba = ( part[i].start + part[i].length - 1 );
  196. /* Initialise log buffer */
  197. memset ( &int13con_buffer[ sizeof ( *hdr ) ], 0,
  198. ( sizeof ( int13con_buffer ) - sizeof ( *hdr ) ) );
  199. int13con_offset = sizeof ( hdr->magic );
  200. return 0;
  201. }
  202. DBG ( "INT13CON found no log partition\n" );
  203. return -ENOENT;
  204. }
  205. /**
  206. * Initialise INT13 console
  207. *
  208. */
  209. static void int13con_init ( void ) {
  210. uint8_t error;
  211. uint16_t check;
  212. unsigned int discard_c;
  213. unsigned int discard_d;
  214. int rc;
  215. /* Check for INT13 extensions */
  216. __asm__ __volatile__ ( REAL_CODE ( "int $0x13\n\t"
  217. "setc %%al\n\t" )
  218. : "=a" ( error ), "=b" ( check ),
  219. "=c" ( discard_c ), "=d" ( discard_d )
  220. : "0" ( INT13_EXTENSION_CHECK << 8 ),
  221. "1" ( 0x55aa ), "3" ( INT13CON_DRIVE ) );
  222. if ( error || ( check != 0xaa55 ) ) {
  223. DBG ( "INT13CON missing extensions (%02x,%04x)\n",
  224. error, check );
  225. return;
  226. }
  227. /* Store original INT13 vector */
  228. copy_from_real ( &int13con_vector, 0, ( 0x13 * 4 ),
  229. sizeof ( int13con_vector ) );
  230. DBG ( "INT13CON using original INT13 vector %04x:%04x\n",
  231. int13con_vector.segment, int13con_vector.offset );
  232. /* Locate log partition */
  233. if ( ( rc = int13con_find() ) != 0)
  234. return;
  235. /* Enable console */
  236. int13con.disabled = 0;
  237. }
  238. /**
  239. * INT13 console initialisation function
  240. */
  241. struct init_fn int13con_init_fn __init_fn ( INIT_CONSOLE ) = {
  242. .initialise = int13con_init,
  243. };
  244. /** INT13 console driver */
  245. struct console_driver int13con __console_driver = {
  246. .putchar = int13con_putchar,
  247. .disabled = CONSOLE_DISABLED,
  248. .usage = CONSOLE_INT13,
  249. };