
       SYSTEM_SERVICES	 =  21		; Bios system services
	      A20_BIOS	 =  36		; Function 0x24
	   A20_DISABLE	 =   0
	    A20_ENABLE	 =   1
	   A20_ENABLED	 =   A20_ENABLE
	     A20_QUERY	 =   2
	   A20_CHECK92	 =   3

	  NO_BIOS_FUNC	 = 134		; SYSTEM_SERVICES not avaliable
		   BDA	 =  64		; Segment pointer to BIOS Data Area

    KEYBOARD	=     22		; BIOS interrupt 0x16
     RE_BOOT	=     25		;                0x19
       UCASE	=     95		; 0x5f

 SET_CUR_POS	=      2		; Set cursor position
 SELECT_PAGE	=      5		; Set cursor position
       VIDEO	=     16
	 TTY	=     14

; ============================================================================================
;       Values as passed by Boot.asm, but may be different if  2ND_STAGE was changed in
;       source.

;               ES = 0100     AX = 003E       CX = 0002
;               CS = 0100     DX = 0080       BX = 0000
;               SS = 91C0     SP = DFE2       BP = DFE4
;               DS = 91C0     SI = DF9A       DI = 0050

; --------------------------------------------------------------------------------------------

    ; Set ES to top of first 64k block of memory.

	mov	ax, 1000h
	mov	es, ax			; Point to top of first 64k block.
	jmp	GetMemMap		; Bounce over local data and subroutine

		db	-1		; So Magic is evenly aligned without NOP
  Magic:	db	'PAMS'

		align	16		; Eeeks out a few ticks I think being aligned
; --------------------------------------------------------------------------------------------
  GetMapEntry:

    ; Decrement segment pointer by two to make room for next 20 or 24 byte entry. Each entry
    ; will be padded by 12 or 8 bytes.

	mov	ax, es
	dec	ax
	dec	ax
	mov	es, ax			; Bump segment back 32 bytes

	mov	ax, 0E820h		; Copy E820
	mov	cl, 24			; Default size of entry
	mov    [es:20], si		; ACPI compatiblity

	push   edx			; Incase BIOS trashes this
	int    SYSTEM_SERVICES
	pop    edx

	ret				; Returns with CF set or cleared
		align	4
; --------------------------------------------------------------------------------------------
  GetMemMap:

    ; Do initial setup of registers that aren't done in service subroutine.

	xor	ebx, ebx		; EBX intially zero.
	mov	ecx, ebx
	mov	 di,  cx		; DI will always be zero
	mov	esi, ebx
	inc	 si			; Used to initialize APCI 3.0
	mov	edx, [cs:Magic] 	; = "SMAP"
	push	0			; Counter

    ; Get initial entry

	call	GetMapEntry
	jc	.Error
	cmp	eax, edx		; Was magic returned in EAX?
	jnz	.Error
	test	ebx, ebx
	jnz	@F

    ; Not sure what kind of error trapping I'll do here.
  .Error:
	hlt
	jmp	.Error

  .NextEntry:
	call	GetMapEntry
	jc	.Done
	test	ebx, ebx
	jz	.Done
	or	 cl, cl
	jnz	 @F

    ; Now that we know that we have a null entry, ES has to be unrolled so we don't have
    ; a blank entry in list.

  .Skip:
	push	 es
	add	word [esp], 2		; Bump segment pointer ahead 32 bytes
	pop	 es
	jmp	.NextEntry

   @@:	cmp	 cl, 20 		; Is it APCI entry
	jz	 @F

	test	byte [20], 1		; Ignore set?
	jz	.Skip

   @@:	mov	eax, [es:8]
	or	eax, [es:12]		; ZF=1 if entry has null length
	jz	.Skip

	inc	word [esp]		; Bump counter
	jmp	.NextEntry

  .Done:
	inc	word [esp]		; Bump count to represent actual list size @ BP - 4
	mov	 ax, es
	shl	 ax, 4			; Convert segment to offset.
	push	 ax			; @ BP - 6
