|  | @@ -24,7 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER )
 | 
		
	
		
			
			| 24 | 24 |  #define CR0_PE 1
 | 
		
	
		
			
			| 25 | 25 |  
 | 
		
	
		
			
			| 26 | 26 |  /****************************************************************************
 | 
		
	
		
			
			| 27 |  | - * flatten_real_mode (real-mode far call)
 | 
		
	
		
			
			|  | 27 | + * flatten_real_mode
 | 
		
	
		
			
			| 28 | 28 |   *
 | 
		
	
		
			
			| 29 | 29 |   * Set up 4GB segment limits
 | 
		
	
		
			
			| 30 | 30 |   *
 | 
		
	
	
		
			
			|  | @@ -63,7 +63,6 @@ flatten_saved_gdt:
 | 
		
	
		
			
			| 63 | 63 |  
 | 
		
	
		
			
			| 64 | 64 |  	.section ".text16.early", "awx", @progbits
 | 
		
	
		
			
			| 65 | 65 |  	.code16
 | 
		
	
		
			
			| 66 |  | -	.globl	flatten_real_mode
 | 
		
	
		
			
			| 67 | 66 |  flatten_real_mode:
 | 
		
	
		
			
			| 68 | 67 |  	/* Preserve registers and flags */
 | 
		
	
		
			
			| 69 | 68 |  	pushfl
 | 
		
	
	
		
			
			|  | @@ -126,7 +125,7 @@ flatten_real_mode:
 | 
		
	
		
			
			| 126 | 125 |  	popw	%si
 | 
		
	
		
			
			| 127 | 126 |  	popl	%eax
 | 
		
	
		
			
			| 128 | 127 |  	popfl
 | 
		
	
		
			
			| 129 |  | -	lret
 | 
		
	
		
			
			|  | 128 | +	ret
 | 
		
	
		
			
			| 130 | 129 |  	.size flatten_real_mode, . - flatten_real_mode
 | 
		
	
		
			
			| 131 | 130 |  
 | 
		
	
		
			
			| 132 | 131 |  	.section ".text16.early", "awx", @progbits
 | 
		
	
	
		
			
			|  | @@ -139,3 +138,281 @@ set_seg_base:
 | 
		
	
		
			
			| 139 | 138 |  	andb	$0x0f, 4(%si)
 | 
		
	
		
			
			| 140 | 139 |  	ret
 | 
		
	
		
			
			| 141 | 140 |  	.size set_seg_base, . - set_seg_base
 | 
		
	
		
			
			|  | 141 | +
 | 
		
	
		
			
			|  | 142 | +/****************************************************************************
 | 
		
	
		
			
			|  | 143 | + * test_a20_short, test_a20_long
 | 
		
	
		
			
			|  | 144 | + *
 | 
		
	
		
			
			|  | 145 | + * Check to see if A20 line is enabled
 | 
		
	
		
			
			|  | 146 | + *
 | 
		
	
		
			
			|  | 147 | + * Parameters:
 | 
		
	
		
			
			|  | 148 | + *   none
 | 
		
	
		
			
			|  | 149 | + * Returns:
 | 
		
	
		
			
			|  | 150 | + *   CF set if A20 line is not enabled
 | 
		
	
		
			
			|  | 151 | + * Corrupts:
 | 
		
	
		
			
			|  | 152 | + *   none
 | 
		
	
		
			
			|  | 153 | + ****************************************************************************
 | 
		
	
		
			
			|  | 154 | + */
 | 
		
	
		
			
			|  | 155 | +#define TEST_A20_SHORT_MAX_RETRIES 0x20
 | 
		
	
		
			
			|  | 156 | +#define TEST_A20_LONG_MAX_RETRIES 0x200000
 | 
		
	
		
			
			|  | 157 | +	.section ".text16.early", "awx", @progbits
 | 
		
	
		
			
			|  | 158 | +	.code16
 | 
		
	
		
			
			|  | 159 | +test_a20_short:
 | 
		
	
		
			
			|  | 160 | +	pushl	%ecx
 | 
		
	
		
			
			|  | 161 | +	movl	$TEST_A20_SHORT_MAX_RETRIES, %ecx
 | 
		
	
		
			
			|  | 162 | +	jmp	1f
 | 
		
	
		
			
			|  | 163 | +	.size	test_a20_short, . - test_a20_short
 | 
		
	
		
			
			|  | 164 | +test_a20_long:
 | 
		
	
		
			
			|  | 165 | +	pushl	%ecx
 | 
		
	
		
			
			|  | 166 | +	movl	$TEST_A20_LONG_MAX_RETRIES, %ecx
 | 
		
	
		
			
			|  | 167 | +1:	pushw	%ax
 | 
		
	
		
			
			|  | 168 | +
 | 
		
	
		
			
			|  | 169 | +	/* Flatten real mode so we can access the test pattern's 1MB offset */
 | 
		
	
		
			
			|  | 170 | +	call	flatten_real_mode
 | 
		
	
		
			
			|  | 171 | +
 | 
		
	
		
			
			|  | 172 | +2:	/* Modify and check test pattern; succeed if we see a difference */
 | 
		
	
		
			
			|  | 173 | +	incw	%cs:test_a20_data
 | 
		
	
		
			
			|  | 174 | +	addr32 movw %cs:(test_a20_data + 0x100000 ), %ax
 | 
		
	
		
			
			|  | 175 | +	cmpw	%cs:test_a20_data, %ax
 | 
		
	
		
			
			|  | 176 | +	clc
 | 
		
	
		
			
			|  | 177 | +	jnz	99f
 | 
		
	
		
			
			|  | 178 | +
 | 
		
	
		
			
			|  | 179 | +	/* Delay and retry */
 | 
		
	
		
			
			|  | 180 | +	outb	%al, $0x80
 | 
		
	
		
			
			|  | 181 | +	addr32 loop 2b
 | 
		
	
		
			
			|  | 182 | +	stc
 | 
		
	
		
			
			|  | 183 | +
 | 
		
	
		
			
			|  | 184 | +99:	/* Restore registers and return */
 | 
		
	
		
			
			|  | 185 | +	popw	%ax
 | 
		
	
		
			
			|  | 186 | +	popl	%ecx
 | 
		
	
		
			
			|  | 187 | +	ret
 | 
		
	
		
			
			|  | 188 | +	.size	test_a20_long, . - test_a20_long
 | 
		
	
		
			
			|  | 189 | +
 | 
		
	
		
			
			|  | 190 | +	.section ".text16.early.data", "aw", @progbits
 | 
		
	
		
			
			|  | 191 | +	.align	2
 | 
		
	
		
			
			|  | 192 | +test_a20_data:
 | 
		
	
		
			
			|  | 193 | +	.word	0xdead
 | 
		
	
		
			
			|  | 194 | +	.size	test_a20_data, . - test_a20_data
 | 
		
	
		
			
			|  | 195 | +
 | 
		
	
		
			
			|  | 196 | +/****************************************************************************
 | 
		
	
		
			
			|  | 197 | + * enable_a20_bios
 | 
		
	
		
			
			|  | 198 | + *
 | 
		
	
		
			
			|  | 199 | + * Try enabling A20 line via BIOS
 | 
		
	
		
			
			|  | 200 | + *
 | 
		
	
		
			
			|  | 201 | + * Parameters:
 | 
		
	
		
			
			|  | 202 | + *   none
 | 
		
	
		
			
			|  | 203 | + * Returns:
 | 
		
	
		
			
			|  | 204 | + *   CF set if A20 line is not enabled
 | 
		
	
		
			
			|  | 205 | + * Corrupts:
 | 
		
	
		
			
			|  | 206 | + *   none
 | 
		
	
		
			
			|  | 207 | + ****************************************************************************
 | 
		
	
		
			
			|  | 208 | + */
 | 
		
	
		
			
			|  | 209 | +	.section ".text16.early", "awx", @progbits
 | 
		
	
		
			
			|  | 210 | +	.code16
 | 
		
	
		
			
			|  | 211 | +enable_a20_bios:
 | 
		
	
		
			
			|  | 212 | +	/* Preserve registers */
 | 
		
	
		
			
			|  | 213 | +	pushw	%ax
 | 
		
	
		
			
			|  | 214 | +
 | 
		
	
		
			
			|  | 215 | +	/* Attempt INT 15,2401 */
 | 
		
	
		
			
			|  | 216 | +	movw	$0x2401, %ax
 | 
		
	
		
			
			|  | 217 | +	int	$0x15
 | 
		
	
		
			
			|  | 218 | +	jc	99f
 | 
		
	
		
			
			|  | 219 | +
 | 
		
	
		
			
			|  | 220 | +	/* Check that success was really successful */
 | 
		
	
		
			
			|  | 221 | +	call	test_a20_short
 | 
		
	
		
			
			|  | 222 | +
 | 
		
	
		
			
			|  | 223 | +99:	/* Restore registers and return */
 | 
		
	
		
			
			|  | 224 | +	popw	%ax
 | 
		
	
		
			
			|  | 225 | +	ret
 | 
		
	
		
			
			|  | 226 | +	.size	enable_a20_bios, . - enable_a20_bios
 | 
		
	
		
			
			|  | 227 | +
 | 
		
	
		
			
			|  | 228 | +/****************************************************************************
 | 
		
	
		
			
			|  | 229 | + * enable_a20_kbc
 | 
		
	
		
			
			|  | 230 | + *
 | 
		
	
		
			
			|  | 231 | + * Try enabling A20 line via keyboard controller
 | 
		
	
		
			
			|  | 232 | + *
 | 
		
	
		
			
			|  | 233 | + * Parameters:
 | 
		
	
		
			
			|  | 234 | + *   none
 | 
		
	
		
			
			|  | 235 | + * Returns:
 | 
		
	
		
			
			|  | 236 | + *   CF set if A20 line is not enabled
 | 
		
	
		
			
			|  | 237 | + * Corrupts:
 | 
		
	
		
			
			|  | 238 | + *   none
 | 
		
	
		
			
			|  | 239 | + ****************************************************************************
 | 
		
	
		
			
			|  | 240 | + */
 | 
		
	
		
			
			|  | 241 | +#define KC_RDWR		0x60
 | 
		
	
		
			
			|  | 242 | +#define KC_RDWR_SET_A20		0xdf
 | 
		
	
		
			
			|  | 243 | +#define	KC_CMD		0x64
 | 
		
	
		
			
			|  | 244 | +#define KC_CMD_WOUT		0xd1
 | 
		
	
		
			
			|  | 245 | +#define KC_CMD_NULL		0xff
 | 
		
	
		
			
			|  | 246 | +#define KC_STATUS	0x64
 | 
		
	
		
			
			|  | 247 | +#define KC_STATUS_OBUF_FULL	0x01
 | 
		
	
		
			
			|  | 248 | +#define KC_STATUS_IBUF_FULL	0x02
 | 
		
	
		
			
			|  | 249 | +#define KC_MAX_RETRIES	100000
 | 
		
	
		
			
			|  | 250 | +	.section ".text16.early", "awx", @progbits
 | 
		
	
		
			
			|  | 251 | +	.code16
 | 
		
	
		
			
			|  | 252 | +enable_a20_kbc:
 | 
		
	
		
			
			|  | 253 | +	/* Preserve registers */
 | 
		
	
		
			
			|  | 254 | +	pushw	%ax
 | 
		
	
		
			
			|  | 255 | +
 | 
		
	
		
			
			|  | 256 | +	/* Try keyboard controller */
 | 
		
	
		
			
			|  | 257 | +	call	empty_kbc
 | 
		
	
		
			
			|  | 258 | +	movb	$KC_CMD_WOUT, %al
 | 
		
	
		
			
			|  | 259 | +	outb	%al, $KC_CMD
 | 
		
	
		
			
			|  | 260 | +	call	empty_kbc
 | 
		
	
		
			
			|  | 261 | +	movb	$KC_RDWR_SET_A20, %al
 | 
		
	
		
			
			|  | 262 | +	outb	%al, $KC_RDWR
 | 
		
	
		
			
			|  | 263 | +	call	empty_kbc
 | 
		
	
		
			
			|  | 264 | +	movb	$KC_CMD_NULL, %al
 | 
		
	
		
			
			|  | 265 | +	outb	%al, $KC_CMD
 | 
		
	
		
			
			|  | 266 | +	call	empty_kbc
 | 
		
	
		
			
			|  | 267 | +
 | 
		
	
		
			
			|  | 268 | +	/* Check to see if it worked */
 | 
		
	
		
			
			|  | 269 | +	call	test_a20_long
 | 
		
	
		
			
			|  | 270 | +
 | 
		
	
		
			
			|  | 271 | +	/* Restore registers and return */
 | 
		
	
		
			
			|  | 272 | +	popw	%ax
 | 
		
	
		
			
			|  | 273 | +	ret
 | 
		
	
		
			
			|  | 274 | +	.size	enable_a20_kbc, . - enable_a20_kbc
 | 
		
	
		
			
			|  | 275 | +
 | 
		
	
		
			
			|  | 276 | +	.section ".text16.early", "awx", @progbits
 | 
		
	
		
			
			|  | 277 | +	.code16
 | 
		
	
		
			
			|  | 278 | +empty_kbc:
 | 
		
	
		
			
			|  | 279 | +	/* Preserve registers */
 | 
		
	
		
			
			|  | 280 | +	pushl	%ecx
 | 
		
	
		
			
			|  | 281 | +	pushw	%ax
 | 
		
	
		
			
			|  | 282 | +
 | 
		
	
		
			
			|  | 283 | +	/* Wait for KBC to become empty */
 | 
		
	
		
			
			|  | 284 | +	movl	$KC_MAX_RETRIES, %ecx
 | 
		
	
		
			
			|  | 285 | +1:	outb	%al, $0x80
 | 
		
	
		
			
			|  | 286 | +	inb	$KC_STATUS, %al
 | 
		
	
		
			
			|  | 287 | +	testb	$( KC_STATUS_OBUF_FULL | KC_STATUS_IBUF_FULL ), %al
 | 
		
	
		
			
			|  | 288 | +	jz	99f
 | 
		
	
		
			
			|  | 289 | +	testb	$KC_STATUS_OBUF_FULL, %al
 | 
		
	
		
			
			|  | 290 | +	jz	2f
 | 
		
	
		
			
			|  | 291 | +	outb	%al, $0x80
 | 
		
	
		
			
			|  | 292 | +	inb	$KC_RDWR, %al
 | 
		
	
		
			
			|  | 293 | +2:	addr32 loop 1b
 | 
		
	
		
			
			|  | 294 | +
 | 
		
	
		
			
			|  | 295 | +99:	/* Restore registers and return */
 | 
		
	
		
			
			|  | 296 | +	popw	%ax
 | 
		
	
		
			
			|  | 297 | +	popl	%ecx
 | 
		
	
		
			
			|  | 298 | +	ret
 | 
		
	
		
			
			|  | 299 | +	.size	empty_kbc, . - empty_kbc
 | 
		
	
		
			
			|  | 300 | +
 | 
		
	
		
			
			|  | 301 | +/****************************************************************************
 | 
		
	
		
			
			|  | 302 | + * enable_a20_fast
 | 
		
	
		
			
			|  | 303 | + *
 | 
		
	
		
			
			|  | 304 | + * Try enabling A20 line via "Fast Gate A20"
 | 
		
	
		
			
			|  | 305 | + *
 | 
		
	
		
			
			|  | 306 | + * Parameters:
 | 
		
	
		
			
			|  | 307 | + *   none
 | 
		
	
		
			
			|  | 308 | + * Returns:
 | 
		
	
		
			
			|  | 309 | + *   CF set if A20 line is not enabled
 | 
		
	
		
			
			|  | 310 | + * Corrupts:
 | 
		
	
		
			
			|  | 311 | + *   none
 | 
		
	
		
			
			|  | 312 | + ****************************************************************************
 | 
		
	
		
			
			|  | 313 | + */
 | 
		
	
		
			
			|  | 314 | +#define SCP_A 0x92
 | 
		
	
		
			
			|  | 315 | +	.section ".text16.early", "awx", @progbits
 | 
		
	
		
			
			|  | 316 | +	.code16
 | 
		
	
		
			
			|  | 317 | +enable_a20_fast:
 | 
		
	
		
			
			|  | 318 | +	/* Preserve registers */
 | 
		
	
		
			
			|  | 319 | +	pushw	%ax
 | 
		
	
		
			
			|  | 320 | +
 | 
		
	
		
			
			|  | 321 | +	/* Try "Fast Gate A20" */
 | 
		
	
		
			
			|  | 322 | +	inb	$SCP_A, %al
 | 
		
	
		
			
			|  | 323 | +	orb	$0x02, %al
 | 
		
	
		
			
			|  | 324 | +	andb	$~0x01, %al
 | 
		
	
		
			
			|  | 325 | +	outb	%al, $SCP_A
 | 
		
	
		
			
			|  | 326 | +
 | 
		
	
		
			
			|  | 327 | +	/* Check to see if it worked */
 | 
		
	
		
			
			|  | 328 | +	call	test_a20_long
 | 
		
	
		
			
			|  | 329 | +
 | 
		
	
		
			
			|  | 330 | +	/* Restore registers and return */
 | 
		
	
		
			
			|  | 331 | +	popw	%ax
 | 
		
	
		
			
			|  | 332 | +	ret
 | 
		
	
		
			
			|  | 333 | +	.size	enable_a20_fast, . - enable_a20_fast
 | 
		
	
		
			
			|  | 334 | +
 | 
		
	
		
			
			|  | 335 | +/****************************************************************************
 | 
		
	
		
			
			|  | 336 | + * enable_a20
 | 
		
	
		
			
			|  | 337 | + *
 | 
		
	
		
			
			|  | 338 | + * Try enabling A20 line via any available method
 | 
		
	
		
			
			|  | 339 | + *
 | 
		
	
		
			
			|  | 340 | + * Parameters:
 | 
		
	
		
			
			|  | 341 | + *   none
 | 
		
	
		
			
			|  | 342 | + * Returns:
 | 
		
	
		
			
			|  | 343 | + *   CF set if A20 line is not enabled
 | 
		
	
		
			
			|  | 344 | + * Corrupts:
 | 
		
	
		
			
			|  | 345 | + *   none
 | 
		
	
		
			
			|  | 346 | + ****************************************************************************
 | 
		
	
		
			
			|  | 347 | + */
 | 
		
	
		
			
			|  | 348 | +#define ENABLE_A20_RETRIES 255
 | 
		
	
		
			
			|  | 349 | +	.section ".text16.early", "awx", @progbits
 | 
		
	
		
			
			|  | 350 | +	.code16
 | 
		
	
		
			
			|  | 351 | +enable_a20:
 | 
		
	
		
			
			|  | 352 | +	/* Preserve registers */
 | 
		
	
		
			
			|  | 353 | +	pushl	%ecx
 | 
		
	
		
			
			|  | 354 | +	pushw	%ax
 | 
		
	
		
			
			|  | 355 | +
 | 
		
	
		
			
			|  | 356 | +	/* Check to see if A20 is already enabled */
 | 
		
	
		
			
			|  | 357 | +	call	test_a20_short
 | 
		
	
		
			
			|  | 358 | +	jnc	99f
 | 
		
	
		
			
			|  | 359 | +
 | 
		
	
		
			
			|  | 360 | +	/* Use known working method, if we have one */
 | 
		
	
		
			
			|  | 361 | +	movw	%cs:enable_a20_method, %ax
 | 
		
	
		
			
			|  | 362 | +	testw	%ax, %ax
 | 
		
	
		
			
			|  | 363 | +	jz	1f
 | 
		
	
		
			
			|  | 364 | +	call	*%ax
 | 
		
	
		
			
			|  | 365 | +	jmp	99f
 | 
		
	
		
			
			|  | 366 | +1:
 | 
		
	
		
			
			|  | 367 | +	/* Try all methods in turn until one works */
 | 
		
	
		
			
			|  | 368 | +	movl	$ENABLE_A20_RETRIES, %ecx
 | 
		
	
		
			
			|  | 369 | +2:	movw	$enable_a20_bios, %ax
 | 
		
	
		
			
			|  | 370 | +	movw	%ax, %cs:enable_a20_method
 | 
		
	
		
			
			|  | 371 | +	call	*%ax
 | 
		
	
		
			
			|  | 372 | +	jnc	99f
 | 
		
	
		
			
			|  | 373 | +	movw	$enable_a20_kbc, %ax
 | 
		
	
		
			
			|  | 374 | +	movw	%ax, %cs:enable_a20_method
 | 
		
	
		
			
			|  | 375 | +	call	*%ax
 | 
		
	
		
			
			|  | 376 | +	jnc	99f
 | 
		
	
		
			
			|  | 377 | +	movw	$enable_a20_fast, %ax
 | 
		
	
		
			
			|  | 378 | +	movw	%ax, %cs:enable_a20_method
 | 
		
	
		
			
			|  | 379 | +	call	*%ax
 | 
		
	
		
			
			|  | 380 | +	jnc	99f
 | 
		
	
		
			
			|  | 381 | +	addr32 loop 2b
 | 
		
	
		
			
			|  | 382 | +	/* Failure; exit with carry set */
 | 
		
	
		
			
			|  | 383 | +	movw	$0, %cs:enable_a20_method
 | 
		
	
		
			
			|  | 384 | +	stc
 | 
		
	
		
			
			|  | 385 | +
 | 
		
	
		
			
			|  | 386 | +99:	/* Restore registers and return */
 | 
		
	
		
			
			|  | 387 | +	popw	%ax
 | 
		
	
		
			
			|  | 388 | +	popl	%ecx
 | 
		
	
		
			
			|  | 389 | +	ret
 | 
		
	
		
			
			|  | 390 | +
 | 
		
	
		
			
			|  | 391 | +	.section ".text16.early.data", "aw", @progbits
 | 
		
	
		
			
			|  | 392 | +	.align	2
 | 
		
	
		
			
			|  | 393 | +enable_a20_method:
 | 
		
	
		
			
			|  | 394 | +	.word	0
 | 
		
	
		
			
			|  | 395 | +	.size	enable_a20_method, . - enable_a20_method
 | 
		
	
		
			
			|  | 396 | +
 | 
		
	
		
			
			|  | 397 | +/****************************************************************************
 | 
		
	
		
			
			|  | 398 | + * access_highmem (real mode far call)
 | 
		
	
		
			
			|  | 399 | + *
 | 
		
	
		
			
			|  | 400 | + * Open up access to high memory in flat real mode with A20 enabled
 | 
		
	
		
			
			|  | 401 | + *
 | 
		
	
		
			
			|  | 402 | + * Parameters:
 | 
		
	
		
			
			|  | 403 | + *   none
 | 
		
	
		
			
			|  | 404 | + * Returns:
 | 
		
	
		
			
			|  | 405 | + *   CF set if high memory could not be accessed
 | 
		
	
		
			
			|  | 406 | + * Corrupts:
 | 
		
	
		
			
			|  | 407 | + *   none
 | 
		
	
		
			
			|  | 408 | + ****************************************************************************
 | 
		
	
		
			
			|  | 409 | + */
 | 
		
	
		
			
			|  | 410 | +	.section ".text16.early", "awx", @progbits
 | 
		
	
		
			
			|  | 411 | +	.code16
 | 
		
	
		
			
			|  | 412 | +	.globl	access_highmem
 | 
		
	
		
			
			|  | 413 | +access_highmem:
 | 
		
	
		
			
			|  | 414 | +	/* Enable A20 line */
 | 
		
	
		
			
			|  | 415 | +	call	enable_a20
 | 
		
	
		
			
			|  | 416 | +	/* CPU will be in flat real mode as a result of this call */
 | 
		
	
		
			
			|  | 417 | +	lret
 | 
		
	
		
			
			|  | 418 | +	.size	access_highmem, . - access_highmem
 |