mirror of
				https://github.com/xcat2/xNBA.git
				synced 2025-10-31 11:22:29 +00:00 
			
		
		
		
	Checking in because I don't want to lose this rather neat code for
running the decompresser in 16:16 protected mode using the real-mode stack. However, there's an even simpler way to do it...
This commit is contained in:
		
							
								
								
									
										178
									
								
								src/arch/i386/prefix/libprefix.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								src/arch/i386/prefix/libprefix.S
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,178 @@ | ||||
|  | ||||
| #define CR0_PE 1 | ||||
| 	 | ||||
| 	 | ||||
| 	.arch i386 | ||||
| 	.section ".prefix", "awx", @progbits | ||||
|  | ||||
| /**************************************************************************** | ||||
|  * alloc_basemem (real-mode near call) | ||||
|  * | ||||
|  * Allocate space from base memory via the BIOS free base memory | ||||
|  * counter at 40: 13 | ||||
|  * | ||||
|  * Parameters:  | ||||
|  *   %cx : Number of bytes to allocate | ||||
|  * Returns: | ||||
|  *   %es : Segment address of newly allocated memory | ||||
|  **************************************************************************** | ||||
|  */ | ||||
| 	.section ".prefix" | ||||
| 	.code16 | ||||
| alloc_basemem: | ||||
| 	/* Preserve registers */ | ||||
| 	pushw	%cx | ||||
| 	pushw	%ax | ||||
| 	 | ||||
| 	/* %fs = 0x40, %ax = fbms */ | ||||
| 	movw	$40, %ax | ||||
| 	movw	%ax, %fs | ||||
|  | ||||
| 	/* Round up %cx to nearest kB, subtract from FBMS */ | ||||
| 	addw	$0x03ff, %cx | ||||
| 	andw	$0xfc00, %cx | ||||
| 	shrw	$10, %cx | ||||
| 	movw	%fs:0x13, %ax | ||||
| 	subw	%cx, %ax | ||||
| 	movw	%ax, %fs:0x13 | ||||
|  | ||||
| 	/* Convert to segment address in %es */ | ||||
| 	shlw	$6, %ax | ||||
| 	movw	%ax, %es | ||||
|  | ||||
| 	/* Restore registers and return */ | ||||
| 	popw	%ax | ||||
| 	popw	%cx | ||||
| 	ret | ||||
|  | ||||
|  | ||||
| 	.section ".prefix" | ||||
| 	.align 16 | ||||
| gdt: | ||||
| gdt_limit:		.word gdt_length - 1 | ||||
| gdt_base:		.long gdt | ||||
| 			.word 0 /* padding */ | ||||
|  | ||||
| cs16: 		/* 16 bit code segment, base at real-mode %cs:0000 */ | ||||
| 	.equ	CS16, cs16 - gdt | ||||
| 	.word	0xffff, 0 | ||||
| 	.byte	0, 0x9b, 0, 0 | ||||
| 	 | ||||
| ss16:		/* 16 bit stack segment, base at real-mode %ss:0000 */ | ||||
| 	.equ	SS16, ss16 - gdt | ||||
| 	.word	0xffff, 0 | ||||
| 	.byte	0, 0x93, 0, 0 | ||||
|  | ||||
| flat_ds:	/* 16 bit data segment, zero base, 4GB limit */ | ||||
| 	.equ	FLAT_DS, flat_ds - gdt | ||||
| 	.word	0xffff, 0 | ||||
| 	.byte	0, 0x9f, 0xcf, 0 | ||||
| 	 | ||||
| gdt_end: | ||||
| 	.equ	gdt_length, gdt_end - gdt | ||||
|  | ||||
|  | ||||
|  | ||||
| 	 | ||||
| 	.section ".prefix" | ||||
| 	.code16 | ||||
| prot16_call: | ||||
|  | ||||
|  | ||||
| 	/* Install .data16 to top of base memory */ | ||||
| 	movw	%cs, %ax | ||||
| 	addw	$_data16_load_offset_pgh, %ax | ||||
| 	movw	%ax, %ds | ||||
| 	movw	$_data16_size, %cx | ||||
| 	call	alloc_basemem | ||||
| 	xorw	%si, %si | ||||
| 	xorw	%di, %di	 | ||||
| 	movw	$_data16_progbits_size, %cx | ||||
| 	rep movsb /* or "call decompress16" */ | ||||
|  | ||||
| 	/* Install .code16 to top of base memory */ | ||||
| 	movw	%cs, %ax | ||||
| 	addw	$_code16_load_offset_pgh, %ax | ||||
| 	movw	%ax, %ds | ||||
| 	movw	$_code16_size, %cx | ||||
| 	call	alloc_basemem | ||||
| 	xorw	%si, %si | ||||
| 	xorw	%di, %di	 | ||||
| 	rep movsb /* or "call decompress16" */ | ||||
| 	 | ||||
| 	/* Push flags and real-mode segment registers */ | ||||
| 	pushfl | ||||
| 	push	%gs | ||||
| 	push	%fs | ||||
| 	push	%es | ||||
| 	push	%ds | ||||
| 	push	%ss | ||||
| 	push	%cs | ||||
|  | ||||
| 	/* Physical address of %cs:0000 to %ebx, of %ss:0000 to %eax */ | ||||
| 	xorl	%ebx, %ebx | ||||
| 	movw	%cs, %bx | ||||
| 	shll	$4, %ebx | ||||
| 	xorl	%eax, %eax | ||||
| 	movw	%ss, %ax | ||||
| 	shll	$4, %eax | ||||
| 	 | ||||
| 	/* Set up GDT and switch to protected mode */ | ||||
| 	addl	%ebx, %cs:gdt_base | ||||
| 	orl	%ebx, %cs:(cs16+2) | ||||
| 	orl	%eax, %cs:(ss16+2) | ||||
| 	cli | ||||
| 	data32 lgdt	%cs:gdt | ||||
| 	movl	%cr0, %eax | ||||
| 	orb	$CR0_PE, %al | ||||
| 	movl	%eax, %cr0 | ||||
| 	data32 ljmp	$CS16, $1f | ||||
| 1:	movw	$SS16, %ax | ||||
| 	movw	%ax, %ss | ||||
| 	movw	$FLAT_DS, %ax | ||||
| 	movw	%ax, %ds | ||||
| 	movw	%ax, %es | ||||
| 	movw	%ax, %fs | ||||
| 	movw	%ax, %gs | ||||
|  | ||||
| 	/* Install .text and .data to 2MB mark.  Use 2MB to avoid | ||||
| 	 * having to deal with A20. | ||||
| 	 */ | ||||
| 	leal	_text_load_offset(%ebx), %esi | ||||
| 	movl	$( 2 * 1024 * 1024 ), %edi | ||||
| 	movl	$_text_and_data_progbits_size, %ecx | ||||
| 	addr32 rep movsb /* or "call decompress16" */ | ||||
| 	 | ||||
| 	/* Restore real-mode segment limits */ | ||||
| 	movw	%ss, %ax | ||||
| 	movw	%ax, %ds | ||||
| 	movw	%ax, %es | ||||
| 	movw	%ax, %fs | ||||
| 	movw	%ax, %gs | ||||
| 	 | ||||
| 	/* Return to real mode, restore segment registers and flags */ | ||||
| 	pushw	$1f | ||||
| 	movl	%cr0, %eax | ||||
| 	andb	$0!CR0_PE, %al | ||||
| 	movl	%eax, %cr0 | ||||
| 	lret	/* used as equivalent of pop %cs */ | ||||
| 1:	pop	%ss | ||||
| 	pop	%ds | ||||
| 	pop	%es | ||||
| 	pop	%fs | ||||
| 	pop	%gs | ||||
| 	popfl | ||||
|  | ||||
| 	/* Call init_gdt */ | ||||
| 	pushw	%cs | ||||
| 	pushw	$1f | ||||
| 	pushw	%es | ||||
| 	pushw	$init_gdt | ||||
| 	lret /* lcall %es:init_gdt */ | ||||
| 1:	 | ||||
| 	 | ||||
|  | ||||
| 	 | ||||
| 	ret | ||||
| 	 | ||||
|  | ||||
		Reference in New Issue
	
	Block a user