2 * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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
33 /** Emulated drive number */
34 static int vdisk_drive
;
37 * Initialise emulation
39 * @ret drive Emulated drive number
41 int initialise_int13 ( void ) {
43 /* Determine drive number */
44 vdisk_drive
= ( 0x80 | INT13_DRIVE_COUNT
++ );
45 DBG ( "Emulating drive %#02x\n", vdisk_drive
);
51 * INT 13, 08 - Get drive parameters
53 * @ret ch Low bits of maximum cylinder number
54 * @ret cl (bits 7:6) High bits of maximum cylinder number
55 * @ret cl (bits 5:0) Maximum sector number
56 * @ret dh Maximum head number
57 * @ret dl Number of drives
60 static void int13_get_parameters ( struct bootapp_callback_params
*params
) {
61 unsigned int max_cylinder
= ( VDISK_CYLINDERS
- 1 );
62 unsigned int max_head
= ( VDISK_HEADS
- 1 );
63 unsigned int max_sector
= ( VDISK_SECTORS_PER_TRACK
- 0 /* sic */ );
64 unsigned int num_drives
;
65 unsigned int min_num_drives
;
67 /* Calculate number of drives to report */
68 num_drives
= INT13_DRIVE_COUNT
;
69 min_num_drives
= ( ( vdisk_drive
& 0x7f ) + 1 );
70 if ( num_drives
< min_num_drives
)
71 num_drives
= min_num_drives
;
73 /* Fill in drive parameters */
74 params
->ch
= ( max_cylinder
& 0xff );
75 params
->cl
= ( ( ( max_cylinder
>> 8 ) << 6 ) | max_sector
);
76 params
->dh
= max_head
;
77 params
->dl
= num_drives
;
78 DBG2 ( "Get parameters: C/H/S = %d/%d/%d, drives = %d\n",
79 ( max_cylinder
+ 1 ), ( max_head
+ 1 ), max_sector
, num_drives
);
86 * INT 13, 15 - Get disk type
88 * @ret cx:dx Sector count
91 static void int13_get_disk_type ( struct bootapp_callback_params
*params
) {
92 uint32_t sector_count
= VDISK_COUNT
;
93 uint8_t drive_type
= INT13_DISK_TYPE_HDD
;
95 /* Fill in disk type */
96 params
->cx
= ( sector_count
>> 16 );
97 params
->dx
= ( sector_count
& 0xffff );
98 params
->ah
= drive_type
;
99 DBG2 ( "Get disk type: sectors = %#08x, type = %d\n",
100 sector_count
, drive_type
);
104 * INT 13, 41 - Extensions installation check
108 * @ret cx Extensions API support bitmap
109 * @ret ah API version
111 static void int13_extension_check ( struct bootapp_callback_params
*params
) {
113 /* Fill in extension information */
115 params
->cx
= INT13_EXTENSION_LINEAR
;
116 params
->ah
= INT13_EXTENSION_VER_1_X
;
117 DBG2 ( "Extensions installation check\n" );
121 * INT 13, 48 - Get extended parameters
123 * @v ds:si Drive parameter table
124 * @ret ah Status code
127 int13_get_extended_parameters ( struct bootapp_callback_params
*params
) {
128 struct int13_disk_parameters
*disk_params
;
130 /* Fill in extended parameters */
131 disk_params
= REAL_PTR ( params
->ds
, params
->si
);
132 memset ( disk_params
, 0, sizeof ( *disk_params
) );
133 disk_params
->bufsize
= sizeof ( *disk_params
);
134 disk_params
->flags
= INT13_FL_DMA_TRANSPARENT
;
135 disk_params
->cylinders
= VDISK_CYLINDERS
;
136 disk_params
->heads
= VDISK_HEADS
;
137 disk_params
->sectors_per_track
= VDISK_SECTORS_PER_TRACK
;
138 disk_params
->sectors
= VDISK_COUNT
;
139 disk_params
->sector_size
= VDISK_SECTOR_SIZE
;
140 DBG2 ( "Get extended parameters: C/H/S = %d/%d/%d, sectors = %#08llx "
141 "(%d bytes)\n", disk_params
->cylinders
, disk_params
->heads
,
142 disk_params
->sectors_per_track
, disk_params
->sectors
,
143 disk_params
->sector_size
);
150 * INT 13, 42 - Extended read
152 * @v ds:si Disk address packet
153 * @ret ah Status code
155 static void int13_extended_read ( struct bootapp_callback_params
*params
) {
156 struct int13_disk_address
*disk_address
;
159 /* Read from emulated disk */
160 disk_address
= REAL_PTR ( params
->ds
, params
->si
);
161 data
= REAL_PTR ( disk_address
->buffer
.segment
,
162 disk_address
->buffer
.offset
);
163 vdisk_read ( disk_address
->lba
, disk_address
->count
, data
);
170 * Emulate INT 13 drive
172 * @v params Parameters
174 void emulate_int13 ( struct bootapp_callback_params
*params
) {
175 int command
= params
->ah
;
176 int drive
= params
->dl
;
178 unsigned long eflags
;
180 if ( drive
== vdisk_drive
) {
182 /* Emulated drive - handle internally */
184 /* Populate eflags with a sensible starting value */
185 __asm__ ( "pushf\n\t"
188 params
->eflags
= ( eflags
& ~CF
);
192 case INT13_GET_PARAMETERS
:
193 int13_get_parameters ( params
);
195 case INT13_GET_DISK_TYPE
:
196 int13_get_disk_type ( params
);
198 case INT13_EXTENSION_CHECK
:
199 int13_extension_check ( params
);
201 case INT13_GET_EXTENDED_PARAMETERS
:
202 int13_get_extended_parameters ( params
);
204 case INT13_EXTENDED_READ
:
205 int13_extended_read ( params
);
208 DBG ( "Unrecognised INT 13,%02x\n", command
);
209 params
->eflags
|= CF
;
215 /* Pass through command to underlying INT 13 */
216 call_interrupt ( params
);
218 /* Modify drive count, if applicable */
219 if ( command
== INT13_GET_PARAMETERS
) {
220 min_num_drives
= ( ( vdisk_drive
& 0x7f ) + 1 );
221 if ( params
->dl
< min_num_drives
)
222 params
->dl
= min_num_drives
;