;	AUTO-GENERATED SYMBOL LIST
;	IMPORTS:
;	  NKConsoleLog
;	    printw
;	  NKIndex
;	    DeleteID
;	    GetNextIDOfClass
;	    LookupID
;	    MakeID
;	  NKMPCalls
;	    CommonMPCallReturnPath
;	    ReleaseAndMPCallWasBad
;	    ReleaseAndReturnMPCall
;	    ReleaseAndReturnMPCallInvalidIDErr
;	    ReleaseAndReturnMPCallOOM
;	    ReleaseAndReturnMPCallPrivilegedErr
;	    ReleaseAndReturnParamErrFromMPCall
;	    ReleaseAndReturnZeroFromMPCall
;	    ReleaseAndScrambleMPCall
;	    ReturnMPCallInvalidIDErr
;	    ReturnMPCallOOM
;	    ReturnParamErrFromMPCall
;	    ReturnZeroFromMPCall
;	    major_0x0b0cc
;	  NKPoolAllocator
;	    PoolAllocClear
;	    PoolFree
;	  NKSync
;	    CauseNotification
;	    SetEvent
;	  NKThud
;	    panic
;	EXPORTS:
;	  CreateArea (=> NKVMCalls)
;	  CreateAreasFromPageMap (=> NKInit)
;	  DeletePTE (=> NKVMCalls)
;	  FindAreaAbove (=> NKInterrupts, NKPaging, NKTasks, NKVMCalls)
;	  FreePageListPush (=> NKInit)
;	  GetPTEFromPLE (=> NKVMCalls)
;	  InitFreePageList (=> NKInit)
;	  InvalPTE (=> NKVMCalls)
;	  MPCall_95_0x254 (=> NKPaging)
;	  NKCreateAddressSpaceSub (=> NKInit)
;	  SetPTE (=> NKVMCalls)
;	  SpaceGetPagePLE (=> NKInterrupts, NKPaging, NKVMCalls)
;	  SpaceL2PIgnoringBATs (=> NKMPCalls)
;	  SpaceL2PUsingBATs (=> NKInterrupts, NKMPCalls)



 #####                              ######                         ###                                    
#     # #####    ##    ####  ###### #     #   ##   #    # #  ####   #   ####  #        ##   #    # #####  
#       #    #  #  #  #    # #      #     #  #  #  ##   # # #    #  #  #      #       #  #  ##   # #    # 
 #####  #    # #    # #      #####  ######  #    # # #  # # #       #   ####  #      #    # # #  # #    # 
      # #####  ###### #      #      #       ###### #  # # # #       #       # #      ###### #  # # #    # 
#     # #      #    # #    # #      #       #    # #   ## # #    #  #  #    # #      #    # #   ## #    # 
 #####  #      #    #  ####  ###### #       #    # #    # #  ####  ###  ####  ###### #    # #    # #####  

SpacePanicIsland
	b		panic



###                #######                      ######                       #                      
 #  #    # # ##### #       #####  ###### ###### #     #   ##    ####  ###### #       #  ####  ##### 
 #  ##   # #   #   #       #    # #      #      #     #  #  #  #    # #      #       # #        #   
 #  # #  # #   #   #####   #    # #####  #####  ######  #    # #      #####  #       #  ####    #   
 #  #  # # #   #   #       #####  #      #      #       ###### #  ### #      #       #      #   #   
 #  #   ## #   #   #       #   #  #      #      #       #    # #    # #      #       # #    #   #   
### #    # #   #   #       #    # ###### ###### #       #    #  ####  ###### ####### #  ####    #   

InitFreePageList
	addi	r9, r1, PSA.FreeList

	InitList	r9, 'PHYS', scratch=r8

	li		r8, 0
	stw		r8, PSA.FreePageCount(r1)
	stw		r8, PSA.UnheldFreePageCount(r1)
	stw		r8, PSA.ZeroedByInitFreeList3(r1)

	lwz		r8, PSA.OtherSystemAddrSpcPtr(r1)
	stw		r8, PSA.OtherSystemAddrSpcPtr2(r1)

	blr



 #####                                       #                                #######                      ######                       #     #               
#     # #####  ######   ##   ##### ######   # #   #####  ######   ##    ####  #       #####   ####  #    # #     #   ##    ####  ###### ##   ##   ##   #####  
#       #    # #       #  #    #   #       #   #  #    # #       #  #  #      #       #    # #    # ##  ## #     #  #  #  #    # #      # # # #  #  #  #    # 
#       #    # #####  #    #   #   #####  #     # #    # #####  #    #  ####  #####   #    # #    # # ## # ######  #    # #      #####  #  #  # #    # #    # 
#       #####  #      ######   #   #      ####### #####  #      ######      # #       #####  #    # #    # #       ###### #  ### #      #     # ###### #####  
#     # #   #  #      #    #   #   #      #     # #   #  #      #    # #    # #       #   #  #    # #    # #       #    # #    # #      #     # #    # #      
 #####  #    # ###### #    #   #   ###### #     # #    # ###### #    #  ####  #       #    #  ####  #    # #       #    #  ####  ###### #     # #    # #      

;	Pretty obvious from log output.

CreateAreasFromPageMap

	;	The kind of crap we have to do without a stack
	mflr	r16
	mfcr	r17
	stw		r16, EWA.SpacesSavedLR(r1)
	stw		r17, EWA.SpacesSavedCR(r1)

	_log	'Converting PMDTs to areas^n'

	lwz		r17, PSA.UnheldFreePageCount(r1)
	lwz		r16, KDP.TotalPhysicalPages(r1)
	add		r17, r17, r16
	stw		r17, PSA.UnheldFreePageCount(r1)


;_______________________________________________________________________
;	Code to increment a loop that:
;		iterates over segmap entries, and
;		iterates over PMDTs, starting at the one
;			ref'd by the segmap entry
;_______________________________________________________________________

	addi	r27, r1, KDP.SegMaps - 8
	lis		r26, 0

@next_segment_entry
	_wlog	'SEGMENT ', r26, '^n'

	lwzu	r25, 8(r27)

	b		@this_pmdt
@next_pmdt
	addi	r25, r25, PMDT.Size
@this_pmdt


;_______________________________________________________________________
;	Now we enter the loop body:
;		r27 points to segmap entry
;		r25 points to the PMDT
;		r26 equals the base address of this segment
;_______________________________________________________________________


	;	Load the contents of the PMDT.

	lwz		r17, PMDT.PBaseAndFlags(r25)
	_wlog	'    PMDT PBaseAndFlags ', r17, ' '

	lhz		r15, PMDT.LBase(r25)
	_wlogh	'LBase ', r15, ' '

	andi.	r8, r17, $800 | $400 | $200		; interested in 3 PBase flags

	lhz		r16, PMDT.PageCount(r25)
	_wlogh	'PageCount ', r16, '^n', scratch=r9	; cannot clobber r8 here


	;	Based on those flags, do one of two things
	cmplwi	r8,      0
	cmplwi	cr1, r8, $800 | $400
	beq		@pmdt_flags_are_zero
	beq		cr1, @pmdt_flags_are_c00

	;	Else if not a full-segment PMDT, next PMDT
	cmplwi	cr2, r15,  0x0000
	cmplwi	cr3, r16,  0xffff
	bne		cr2, @next_pmdt
	bne		cr3, @next_pmdt

	;	Else if there are segments remaining (16 total), next segment.
	addis	r26, r26, 0x1000
	cmplwi	r26, 0					; once it wraps to zero, we're done
	bne		@next_segment_entry

	;	Else create special one-page Areas to catch naughty pointer derefs,
	;	then return.

		;	61F168F1 (magic bus error incantation)

		li		r8, Area.Size
		bl		PoolAllocClear
		mr.		r31, r8
		beq		SpacePanicIsland

		lwz		r8, EWA.PA_CurAddressSpace(r1)
		stw		r8, Area.AddressSpacePtr(r31)

		lisori	r15, 0x68f168f1
		stw		r15, Area.LogicalBase(r31)

		li		r16, 0x1000
		stw		r16, Area.Length(r31)

		lisori	r8, 0x00008000
		stw		r8, Area.LogicalSeparation(r31)

		li		r8, 0
		stw		r8, 0x001c(r31)

		lisori	r8, 0x0000e00c
		stw		r8, 0x0020(r31)

		mr		r8, r31
		bl		CreateArea

		cmpwi	r9, noErr
		beq		@success_68f168f1
		mr		r8, r31
		bl		PoolFree
@success_68f168f1


		;	DEADBEEF (all over the place)

		li		r8, Area.Size
		bl		PoolAllocClear
		mr.		r31, r8
		beq		SpacePanicIsland

		lwz		r8, EWA.PA_CurAddressSpace(r1)
		stw		r8, Area.AddressSpacePtr(r31)

		lisori	r15, 0xdeadbeef
		stw		r15, Area.LogicalBase(r31)

		li		r16, 0x1000
		stw		r16, Area.Length(r31)

		lisori	r8, 0x00008000
		stw		r8, Area.LogicalSeparation(r31)

		li		r8, 0
		stw		r8, 0x001c(r31)

		lisori	r8, 0x0000e00c
		stw		r8, 0x0020(r31)

		mr		r8, r31
		bl		CreateArea

		cmpwi	r9, noErr
		beq		@success_deadbeef
		mr		r8, r31
		bl		PoolFree
@success_deadbeef


		;	Done -- return.
		lwz		r16, EWA.SpacesSavedLR(r1)
		lwz		r17, EWA.SpacesSavedCR(r1)
		mtlr	r16
		mtcr	r17
		blr


	;	ONE OF THE "FLAGS" CASES: all tests bits unset

@pmdt_flags_are_zero
	_clog	'        pmdt_flags_are_zero^n'

	;	Apparently other iterations leave this to find?
		lwz		r8, EWA.SpacesDeferredAreaPtr(r1)
		cmpwi	r8, 0
		beq		@thing_is_zero

		bl		CreateArea
		cmpwi	r9, noErr
		bne		SpacePanicIsland

		li		r8, 0
		stw		r8, EWA.SpacesDeferredAreaPtr(r1)
@thing_is_zero



	li		r8, Area.Size
	bl		PoolAllocClear
	mr.		r31, r8
	beq		SpacePanicIsland

	;	Reload PMDT details
	lwz		r17, PMDT.PBaseAndFlags(r25)
	lhz		r15, PMDT.LBase(r25)
	lhz		r16, PMDT.PageCount(r25)

	;	Why do we need to sign the area? Isn't it 'AREA'?
	lisori	r8, 'area'
	stw		r8, Area.Signature(r31)

	;	Set r15/r16 to true logical base/length
	slwi	r15, r15, 12
	addi	r16, r16, 1
	add		r15, r15, r26			; add a page, I think
	slwi	r16, r16, 12

	lwz		r8, KDP.NanoKernelInfo + NKNanoKernelInfo.blueProcessID(r1)
	stw		r8, Area.ProcessID(r31)

	lwz		r8, EWA.PA_CurAddressSpace(r1)
	stw		r8, Area.AddressSpacePtr(r31)

	stw		r15, Area.LogicalBase(r31)

	stw		r16, Area.Length(r31)
	stw		r16, Area.BytesMapped(r31)

	li		r8, 0
	stw		r8, Area.LogicalSeparation(r31)

	lwz		r18,  0x007c(r31)
	rlwinm	r9, r17,  0,  0, 19
	stw		r9,  0x0070(r31)
	andi.	r16, r17,  0x03
	bne		@_20c
	ori		r17, r17,  0x02
@_20c

	bl		major_0x10d38_0x58
	stw		r18,  0x001c(r31)


@_214



	lisori	r8, 0x0000e00c
	stw		r8, 0x0020(r31)


	;	Try to create the Area. If we succeed then do the next PMDT.
	mr		r8, r31
	bl		CreateArea
	cmpwi	r9, noErr
	mr		r31, r8
	beq		@next_pmdt

	;	If CreateArea failed, assume that it was due to overlap with another Area.

		;	Find that AboveArea that we impinged on (=> r24).
		lwz		r9, Area.LogicalBase(r31)
		lwz		r8, Area.AddressSpacePtr(r31)
		bl		FindAreaAbove
		mr		r24, r8

		;	Shorten our FailedArea to fit below AboveArea.
		lwz		r15, Area.LogicalBase(r31)
		lwz		r16, Area.LogicalBase(r24)
		lwz		r17, Area.LogicalEnd(r31)
		subf.	r16, r15, r16						; r16 = offset of found area from this one
		stw		r17, EWA.SpacesSavedAreaBase(r1)	; ???
		stw		r16, Area.Length(r31)				; we will try again, with no overlap

		beq		@found_area_has_same_base

		;	If FoundArea < FailedArea, panic (impossible for FindAreaAbove to return this)
			bltl	SpacePanicIsland							; below would be impossible

		;	If AboveArea > FailedArea, create NewArea (=> r30)
			mr		r8, r31
			bl		CreateArea

			cmpwi	r9, noErr							; strike three
			mr		r30, r8
			bnel	SpacePanicIsland

			;	If AboveArea.LogicalEnd >= FailedArea.LogicalEnd then continue to next PMDT.
				lwz		r15, Area.LogicalEnd(r24)
				lwz		r16, EWA.SpacesSavedAreaBase(r1)
				subf.	r16, r15, r16
				ble		@next_pmdt

			;	Else replace FailedArea with an Area copied from NewArea
					li		r8, Area.Size
					bl		PoolAllocClear
					mr.		r31, r8
					beq		SpacePanicIsland

					li		r8, Area.Size - 4
@area_copy_loop
					lwzx	r9, r8, r30
					stwx	r9, r8, r31
					cmpwi	r8, 0
					subi	r8, r8, 4
					bgt		@area_copy_loop
@found_area_has_same_base

		;	Else (AboveArea == ThisArea), do nothing special (endif)


		lwz		r9, Area.LogicalBase(r31)

		lwz		r15,  0x0028(r24)
		lwz		r16, EWA.SpacesSavedAreaBase(r1)		; this is FailedArea.LogicalEnd
		subf.	r16, r15, r16
		addi	r15, r15, 1
		blel	SpacePanicIsland

		stw		r16, Area.Length(r31)
		stw		r15, Area.LogicalBase(r31)
		subf	r9, r9, r15
		lwz		r8,  0x0070(r31)
		add		r8, r8, r9
		stw		r8,  0x0070(r31)
		b		@_214




@pmdt_flags_are_c00
	_clog	'        pmdt_flags_are_c00^n'
	li		r8, Area.Size
	bl		PoolAllocClear
	mr.		r31, r8
	beq		SpacePanicIsland

	lwz		r17,  0x0004(r25)
	lhz		r15,  0x0000(r25)
	lhz		r16,  0x0002(r25)
	lis		r8,  0x6172
	ori		r8, r8,  0x6561
	stw		r8, Area.Signature(r31)
	slwi	r15, r15, 12
	addi	r16, r16,  0x01
	add		r15, r15, r26
	slwi	r16, r16, 12
	lwz		r8,  0x0ec0(r1)
	stw		r8, Area.ProcessID(r31)
	lwz		r8, EWA.PA_CurAddressSpace(r1)
	stw		r8, Area.AddressSpacePtr(r31)
	stw		r15, Area.LogicalBase(r31)
	stw		r16, Area.Length(r31)
	stw		r16, Area.BytesMapped(r31)
	li		r8,  0x00
	stw		r8, Area.LogicalSeparation(r31)
	li		r8,  0x07
	stw		r8,  0x001c(r31)
	lis		r8,  0x00
	ori		r8, r8,  0x600c
	stw		r8,  0x0020(r31)
	rlwinm	r8, r17, 22,  0, 29
	stw		r8,  0x0040(r31)
	lwz		r8, Area.Flags(r31)
	ori		r8, r8,  0x40
	lwz		r9, PSA.FreePageCount(r1)
	cmpwi	r9, noErr

	bgt		@_374
	ori		r8, r8,  0x80
@_374

	stw		r8, Area.Flags(r31)
	cmpwi	r15,  0x00

	bne		@_388
	stw		r31, EWA.SpacesDeferredAreaPtr(r1)
	b		@next_pmdt
@_388

	lwz		r18, EWA.SpacesDeferredAreaPtr(r1)
	cmpwi	r18,  0x00
	beq		@_3c8
	lwz		r8,  0x0024(r18)
	lwz		r9,  0x002c(r18)
	add		r19, r8, r9
	cmplw	r19, r15
	bne		@_3c8
	add		r9, r9, r16
	addi	r19, r9, -0x01
	stw		r9,  0x002c(r18)
	stw		r9,  0x0038(r18)
	stw		r19,  0x0028(r18)
	mr		r8, r31
	bl		PoolFree
	b		@next_pmdt
@_3c8

	lwz		r8, Area.Flags(r31)
	ori		r8, r8,  0x80
	stw		r8, Area.Flags(r31)
	mr		r8, r31
	bl		CreateArea
	cmpwi	r9, noErr
	bne		SpacePanicIsland
	b		@next_pmdt



#     # ######   #####               ######                        #####                   #####                                            
##   ## #     # #     # ###### ##### #     #   ##    ####  ###### #     # # ###### ###### #     # #        ##    ####   ####  ######  ####  
# # # # #     # #       #        #   #     #  #  #  #    # #      #       #     #  #      #       #       #  #  #      #      #      #      
#  #  # ######  #  #### #####    #   ######  #    # #      #####   #####  #    #   #####  #       #      #    #  ####   ####  #####   ####  
#     # #       #     # #        #   #       ###### #  ### #            # #   #    #      #       #      ######      #      # #           # 
#     # #       #     # #        #   #       #    # #    # #      #     # #  #     #      #     # #      #    # #    # #    # #      #    # 
#     # #        #####  ######   #   #       #    #  ####  ######  #####  # ###### ######  #####  ###### #    #  ####   ####  ######  ####  

;	The number of page size classes, 1 to n.

;	MPPageSizeClass MPGetPageSizeClasses(void )

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: yes

	DeclareMPCall	68, MPGetPageSizeClasses

MPGetPageSizeClasses

	li		r3, 1
	b		CommonMPCallReturnPath



#     # ######   #####               ######                        #####                  
##   ## #     # #     # ###### ##### #     #   ##    ####  ###### #     # # ###### ###### 
# # # # #     # #       #        #   #     #  #  #  #    # #      #       #     #  #      
#  #  # ######  #  #### #####    #   ######  #    # #      #####   #####  #    #   #####  
#     # #       #     # #        #   #       ###### #  ### #            # #   #    #      
#     # #       #     # #        #   #       #    # #    # #      #     # #  #     #      
#     # #        #####  ######   #   #       #    #  ####  ######  #####  # ###### ###### 

;	The page size in bytes.

;	ByteCount MPGetPageSize(MPPageSizeClass pageClass)

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: yes

	DeclareMPCall	69, MPGetPageSize

MPGetPageSize

	cmpwi	r3, 1
	bne		ReturnParamErrFromMPCall

	lwz		r3, KDP.ProcessorInfo + NKProcessorInfo.PageSize(r1)
	b		CommonMPCallReturnPath



#     # ######   #####                                       #                                               #####                              
##   ## #     # #     # #####  ######   ##   ##### ######   # #   #####  #####  #####  ######  ####   ####  #     # #####    ##    ####  ###### 
# # # # #     # #       #    # #       #  #    #   #       #   #  #    # #    # #    # #      #      #      #       #    #  #  #  #    # #      
#  #  # ######  #       #    # #####  #    #   #   #####  #     # #    # #    # #    # #####   ####   ####   #####  #    # #    # #      #####  
#     # #       #       #####  #      ######   #   #      ####### #    # #    # #####  #           #      #       # #####  ###### #      #      
#     # #       #     # #   #  #      #    #   #   #      #     # #    # #    # #   #  #      #    # #    # #     # #      #    # #    # #      
#     # #        #####  #    # ###### #    #   #   ###### #     # #####  #####  #    # ######  ####   ####   #####  #      #    #  ####  ###### 

;	ARG		MPCoherenceID r3
;	RET		OSStatus r3, MPAddressSpaceID r4

;	Straight MPLibrary wrapper: no
;	In Universal Interfaces: no

	DeclareMPCall	70, MPCreateAddressSpace

MPCreateAddressSpace

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mfsprg	r16, 0
	lwz		r17, EWA.PA_CurTask(r16)

	mr		r8, r3

	lwz		r9, Area.AddressSpacePtr(r17)
	lwz		r16, AddressSpace.Flags(r9)
	rlwinm.	r16, r16, 0, AddressSpace.kFlag30, AddressSpace.kFlag30
	bne		ReleaseAndReturnMPCallOOM

	bl		NKCreateAddressSpaceSub

	_AssertAndRelease	PSA.SchLock, scratch=r16

	mr.		r3, r8
	li		r4, 0
	bne		CommonMPCallReturnPath			; failure

	lwz		r4, AddressSpace.ID(r9)
	b		CommonMPCallReturnPath			; success



#     # #    #  #####                                       #                                               #####                               #####                
##    # #   #  #     # #####  ######   ##   ##### ######   # #   #####  #####  #####  ######  ####   ####  #     # #####    ##    ####  ###### #     # #    # #####  
# #   # #  #   #       #    # #       #  #    #   #       #   #  #    # #    # #    # #      #      #      #       #    #  #  #  #    # #      #       #    # #    # 
#  #  # ###    #       #    # #####  #    #   #   #####  #     # #    # #    # #    # #####   ####   ####   #####  #    # #    # #      #####   #####  #    # #####  
#   # # #  #   #       #####  #      ######   #   #      ####### #    # #    # #####  #           #      #       # #####  ###### #      #            # #    # #    # 
#    ## #   #  #     # #   #  #      #    #   #   #      #     # #    # #    # #   #  #      #    # #    # #     # #      #    # #    # #      #     # #    # #    # 
#     # #    #  #####  #    # ###### #    #   #   ###### #     # #####  #####  #    # ######  ####   ####   #####  #      #    #  ####  ######  #####   ####  #####  

;	ARG		MPCoherenceID r8 owningcgrp		; 0 to use mobo cgrp
;			Process *r9 owningPROC

;	RET		osErr r8
;			AddressSpace *r9

NKCreateAddressSpaceSub
	cmpwi	r8, 0
	mr		r27, r9			; Save the process arg for later
	mflr	r30

	;	Use the motherboard coherence group if none is provided in r8
	bne		@cgrp_provided
	mfsprg	r15, 0
	lwz		r28, EWA.CPUBase + CPU.LLL + LLL.Freeform(r15)

	b		@got_cgrp

@cgrp_provided
	bl		LookupID			; takes id in r8, returns ptr in r8 and kind in r9

	cmpwi	r9, CoherenceGroup.kIDClass
	mr		r28, r8
	bne		@fail_notcgrp
	lwz		r28, CoherenceGroup.LLL + LLL.Next(r28)

@got_cgrp


	;	Read the SpecialPtr of this cgrp element in list of the owning CpuStruct
	;	But why? cgrp.LLL.Freeform does not seem to be set for the mobo cgrp
	lwz		r29, LLL.Freeform(r28)


	;	Boast (including the SpecialPtr)
	_log	'NKCreateAddressSpaceSub - group at 0x'

	mr		r8, r28
	bl		printw

	mr		r8, r29
	bl		printw

	_log	'^n'


	;	Create the AddressSpace
	li		r8, AddressSpace.Size
	bl		PoolAllocClear
	mr.		r31, r8
	beq		@fail_OOM


	;	Give the addr spc a copy of the SpecialPtr of its parent cgrp
	stw		r29, AddressSpace.ParentCoherenceSpecialPtr(r31)


	;	Give the addr spc an ID
	li		r9, AddressSpace.kIDClass
	bl		MakeID

	cmpwi	r8, 0x00
	beq		@fail_MakeID

	stw		r8, AddressSpace.ID(r31)


	;	Increment a counter in the cgrp (modulo a million, fail on overflow)
	lwz		r16, CoherenceGroup.Incrementer(r28)
	addi	r16, r16, 1
	clrlwi.	r16, r16, 12
	beq		@fail_toomanycalls
	stw		r16, CoherenceGroup.Incrementer(r28)


	;	Fill segment register fields in the address space struct like so:
	;	(8 bits = 0x20) || (4 bits = word idx) || (20 bits = prev call count)

	addi	r16, r16, -1
	li		r17, 0x40 - 4
	oris	r16, r16, 0x2000
	addi	r18, r31, AddressSpace.SRs

@fill_loop
	cmpwi	r17, 0
	rlwimi	r16, r17, 18, 8, 11		; = index (15, 14, 13...) << 20
	stwx	r16, r17, r18
	addi	r17, r17, -4
	bne		@fill_loop


	;	Sign the addr spc struct
	lisori	r8, AddressSpace.kSignature
	stw		r8, AddressSpace.Signature(r31)


	;	Create an empty linked list of 'rsrv's (what are they?)
	addi	r16, r31, AddressSpace.RsrvList
	InitList		r16, 'rsrv', scratch=r17


	;	Create a linked list with one Area
	addi	r16, r31, AddressSpace.AreaList
	InitList		r16, 'area', scratch=r17

		;	Allocate the Area, check for errors
		li		r8, Area.Size
		bl		PoolAllocClear
		mr.		r29, r8
		beq		@fail_OOM_again

		;	Sign the Area
		lisori	r8, Area.kSignature
		stw		r8, Area.Signature(r29)

		;	Pop some constants in
		lisori	r8, -1
		stw		r8, Area.LogicalBase(r29)
		stw		r8, Area.LogicalEnd(r29)
		li		r8, 256
		stw		r8, Area.Flags(r29)

		;	Give it a copy of the ID of its parent address space
		lwz		r8, AddressSpace.ID(r31)
		stw		r8, Area.AddressSpaceID(r29)

		;	Point the SpecialPtr to it and insert it in the list
		addi	r16, r31, AddressSpace.AreaList
		addi	r29, r29, Area.LLL
		stw		r16, LLL.Freeform(r29)
		InsertAsPrev	r29, r16, scratch=r17


	;	Point this struct by ID to its owning Process,
	;	and increment a counter in that struct.
	lwz		r18, Process.ID(r27)
	stw		r18, AddressSpace.ProcessID(r31)

	lwz		r17, Process.AddressSpaceCount(r27)
	addi	r17, r17, 1
	stw		r17, Process.AddressSpaceCount(r27)


	;	Done, with no errors
	li		r8, 0			; kMPNoErr
	mr		r9, r31			; ptr to new AddressSpace
	b		@return

@fail_OOM_again
	lwz		r8,Area.ID(r31)

@fail_toomanycalls
	bl		DeleteID
	mr		r8, r31
	bl		PoolFree
	li		r8, kMPInsufficientResourcesErr
	b		@return

@fail_MakeID
	mr		r8, r31
	bl		PoolFree

@fail_OOM
	li		r8, -29294
	b		@return

@fail_notcgrp
	li		r8, kMPInvalidIDErr

@return
	mtlr	r30
	blr



#     # ######  ######                                       #                                               #####                              
##   ## #     # #     # ###### #      ###### ##### ######   # #   #####  #####  #####  ######  ####   ####  #     # #####    ##    ####  ###### 
# # # # #     # #     # #      #      #        #   #       #   #  #    # #    # #    # #      #      #      #       #    #  #  #  #    # #      
#  #  # ######  #     # #####  #      #####    #   #####  #     # #    # #    # #    # #####   ####   ####   #####  #    # #    # #      #####  
#     # #       #     # #      #      #        #   #      ####### #    # #    # #####  #           #      #       # #####  ###### #      #      
#     # #       #     # #      #      #        #   #      #     # #    # #    # #   #  #      #    # #    # #     # #      #    # #    # #      
#     # #       ######  ###### ###### ######   #   ###### #     # #####  #####  #    # ######  ####   ####   #####  #      #    #  ####  ###### 

;	ARG		MPAddressSpaceID r3
;	RET		OSStatus r3

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: no

	DeclareMPCall	71, MPDeleteAddressSpace

MPDeleteAddressSpace

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, AddressSpace.kIDClass
	bne		ReleaseAndReturnMPCallInvalidIDErr

	mr		r31, r8

	;	Die if a Task is using this Space
	lwz		r16, AddressSpace.TaskCount(r31)
	cmpwi	r16, 0
	bne		ReleaseAndReturnMPCallOOM

	;	Die if the Space has a non-empty RsrvList
	addi	r16, r31, AddressSpace.RsrvList
	lwz		r17, AddressSpace.RsrvList + LLL.Next(r31)
	cmpw	r16, r17
	bne		ReleaseAndReturnMPCallOOM

	;	Die if the Space has a non-empty AreaList
	addi	r16, r31, AddressSpace.AreaList
	lwz		r17, AddressSpace.AreaList + LLL.Next(r31)
	cmpw	r16, r17
	bne		ReleaseAndReturnMPCallOOM

	lwz		r8, AddressSpace.ProcessID(r31)
	bl		LookupID
	lwz		r17, Process.AddressSpaceCount(r8)
	subi	r17, r17, 1
	stw		r17, Process.AddressSpaceCount(r8)

	;	Kill
	lwz		r8, AddressSpace.ID(r31)
	bl		DeleteID
	mr		r8, r31
	bl		PoolFree

	b		ReleaseAndReturnZeroFromMPCall



#     # ######   #####                                              #                                               #####                              
##   ## #     # #     # #    # #####  #####  ###### #    # #####   # #   #####  #####  #####  ######  ####   ####  #     # #####    ##    ####  ###### 
# # # # #     # #       #    # #    # #    # #      ##   #   #    #   #  #    # #    # #    # #      #      #      #       #    #  #  #  #    # #      
#  #  # ######  #       #    # #    # #    # #####  # #  #   #   #     # #    # #    # #    # #####   ####   ####   #####  #    # #    # #      #####  
#     # #       #       #    # #####  #####  #      #  # #   #   ####### #    # #    # #####  #           #      #       # #####  ###### #      #      
#     # #       #     # #    # #   #  #   #  #      #   ##   #   #     # #    # #    # #   #  #      #    # #    # #     # #      #    # #    # #      
#     # #        #####   ####  #    # #    # ###### #    #   #   #     # #####  #####  #    # ######  ####   ####   #####  #      #    #  ####  ###### 

;	RET		MPAddressSpaceID r3

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: no

	DeclareMPCall	117, MPCurrentAddressSpace

MPCurrentAddressSpace

	mfsprg	r16, 0
	lwz		r17, EWA.PA_CurAddressSpace(r16)
	lwz		r3, AddressSpace.ID(r17)
	b		CommonMPCallReturnPath



#     # ######  #     #                         #                                               #####                              
##   ## #     # #     #  ####  #    # ######   # #   #####  #####  #####  ######  ####   ####  #     # #####    ##    ####  ###### 
# # # # #     # #     # #    # ##  ## #       #   #  #    # #    # #    # #      #      #      #       #    #  #  #  #    # #      
#  #  # ######  ####### #    # # ## # #####  #     # #    # #    # #    # #####   ####   ####   #####  #    # #    # #      #####  
#     # #       #     # #    # #    # #      ####### #    # #    # #####  #           #      #       # #####  ###### #      #      
#     # #       #     # #    # #    # #      #     # #    # #    # #   #  #      #    # #    # #     # #      #    # #    # #      
#     # #       #     #  ####  #    # ###### #     # #####  #####  #    # ######  ####   ####   #####  #      #    #  ####  ###### 

;	RET		MPAddressSpaceID r3

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: no

	DeclareMPCall	118, MPHomeAddressSpace

MPHomeAddressSpace

	mfsprg	r16, 0
	lwz		r17, EWA.PA_CurTask(r16)
	lwz		r18, Task.OwningProcessPtr(r17)
	lwz		r19, Process.SystemAddressSpacePtr(r18)
	lwz		r3, AddressSpace.ID(r19)
	b		CommonMPCallReturnPath



#     # ######   #####               #######                         #                                               #####                              
##   ## #     # #     # ###### #####    #      ##    ####  #    #   # #   #####  #####  #####  ######  ####   ####  #     # #####    ##    ####  ###### 
# # # # #     # #       #        #      #     #  #  #      #   #   #   #  #    # #    # #    # #      #      #      #       #    #  #  #  #    # #      
#  #  # ######   #####  #####    #      #    #    #  ####  ####   #     # #    # #    # #    # #####   ####   ####   #####  #    # #    # #      #####  
#     # #             # #        #      #    ######      # #  #   ####### #    # #    # #####  #           #      #       # #####  ###### #      #      
#     # #       #     # #        #      #    #    # #    # #   #  #     # #    # #    # #   #  #      #    # #    # #     # #      #    # #    # #      
#     # #        #####  ######   #      #    #    #  ####  #    # #     # #####  #####  #    # ######  ####   ####   #####  #      #    #  ####  ###### 

;	ARG		MPTaskID r3, MPAddressSpaceID r4
;	RET		OSStatus r3

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: no

	DeclareMPCall	119, MPSetTaskAddressSpace

MPSetTaskAddressSpace

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17


	;	Get Task and do some checks

	mr		r8, r3
	bl		LookupID
	mr		r31, r8
	cmpwi	r9, Task.kIDClass
	bne		ReleaseAndReturnMPCallInvalidIDErr

	lwz		r16, Task.Flags(r31)
	mtcr	r16

	li		r3, kMPTaskAbortedErr
	bc		BO_IF, Task.kFlagAborted, ReleaseAndReturnMPCall

	bc		BO_IF_NOT, Task.kFlagStopped, ReleaseAndReturnMPCallOOM

	lbz		r16, Task.State(r31)
	cmpwi	r16, 0
	bne		ReleaseAndReturnMPCallOOM


	;	Get Address Space and do some checks

	mr		r8, r4
	bl		LookupID
	mr		r30, r8

	lwz		r16, Task.ProcessID(r31)
	cmpwi	r9, AddressSpace.kIDClass
	lwz		r17, AddressSpace.ProcessID(r30)
	bne		ReleaseAndReturnMPCallInvalidIDErr

	;	The Task and Address Space must already share a process ID
	cmpw	r16, r17
	bne		ReleaseAndReturnMPCallOOM

	lwz		r17, Task.AddressSpacePtr(r31)

	;	Decrement old Address Space
	lwz		r16, AddressSpace.TaskCount(r17)
	subi	r16, r16, 1
	stw		r16, AddressSpace.TaskCount(r17)

	;	Increment old Address Space
	lwz		r16, AddressSpace.TaskCount(r30)
	addi	r16, r16, 1
	stw		r16, AddressSpace.TaskCount(r30)

	stw		r30, Task.AddressSpacePtr(r31)


	b		ReleaseAndReturnZeroFromMPCall



#     # ######   #####                                       #                         
##   ## #     # #     # #####  ######   ##   ##### ######   # #   #####  ######   ##   
# # # # #     # #       #    # #       #  #    #   #       #   #  #    # #       #  #  
#  #  # ######  #       #    # #####  #    #   #   #####  #     # #    # #####  #    # 
#     # #       #       #####  #      ######   #   #      ####### #####  #      ###### 
#     # #       #     # #   #  #      #    #   #   #      #     # #   #  #      #    # 
#     # #        #####  #    # ###### #    #   #   ###### #     # #    # ###### #    # 

;	This MP call does some of the heavy lifting for the MPLibrary function
;	of the same name. No pages are mapped into the Area.

;	ARG		AddressSpaceID r3 (optional)
;			long r4 PTEConfig
;			long r5 length
;			long r6 LogicalSeparation
;			long r7 flagsAndMinAlign
;			char *r8 LogicalBase
;	RET		r3 OSErr
;			char *r8 LogicalBase
;			AreaID r9

;	Hint: in the 9.2.2 System MPLibrary, MPCreateArea calls a syscall
;	wrapper function at code offset 0x7fa8, with arguments pointing to save
;	locations for r8 and r9.

	DeclareMPCall	72, MPCreateArea

MPCreateArea

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	;	If !r3 then use the current address space
	mr.		r8, r3
	mfsprg	r28, 0
	lwz		r30, EWA.PA_CurAddressSpace(r28)
	beq		@use_current_space

	;	... else use the one specified.
 	bl		LookupID
	cmpwi	r9, AddressSpace.kIDClass
	mr		r30, r8
	bne		ReleaseAndReturnMPCallInvalidIDErr
@use_current_space

	;	Allocate the new Area
	li		r8, Area.Size
	bl		PoolAllocClear
	mr.		r31, r8
	beq		ReleaseAndScrambleMPCall

	;	Populate
	stw		r30, Area.AddressSpacePtr(r31)

	stw		r4, Area.PTEConfig(r31)

	stw		r5, Area.Length(r31)

	lwz		r8, ContextBlock.r6(r6)
	stw		r8, Area.LogicalSeparation(r31)

	lwz		r8, ContextBlock.r7(r6)
	stw		r8, Area.FlagsAndMinAlign(r31)

	lwz		r8, ContextBlock.r8(r6)
	stw		r8, Area.LogicalBase(r31)

	;	"Create" the area
	mr		r8, r31
	bl		CreateArea

	_AssertAndRelease	PSA.SchLock, scratch=r16

	mr.		r3, r9
	bne		@error

	;	CreateArea returned successfully
	lwz		r8, Area.LogicalBase(r31)
	stw		r8, ContextBlock.r8(r6)

	lwz		r8, Area.ID(r31)
	stw		r8, ContextBlock.r9(r6)

	b		CommonMPCallReturnPath

@error
	bl		PoolFree
	b		CommonMPCallReturnPath



 #####                                       #                         
#     # #####  ######   ##   ##### ######   # #   #####  ######   ##   
#       #    # #       #  #    #   #       #   #  #    # #       #  #  
#       #    # #####  #    #   #   #####  #     # #    # #####  #    # 
#       #####  #      ######   #   #      ####### #####  #      ###### 
#     # #   #  #      #    #   #   #      #     # #   #  #      #    # 
 #####  #    # ###### #    #   #   ###### #     # #    # ###### #    # 

;	This function actually gets passed its own structure.
;	What the frick?

;	Always returns via ReturnFromCreateArea

;	ARG		Area *r8
;	RET		ID r8, osErr r9

CreateArea	;	OUTSIDE REFERER

	;	Always returns via ReturnFromCreateArea
	mflr	r16
	mfsprg	r9, 0
	stw		r16, EWA.CreateAreaSavedLR(r9)
	stmw	r25, EWA.CreateAreaSavedR25(r9)

	;	Keep the structure itself in r31 for the duration.
	;	r8 must be used for other things
	mr		r31, r8

	;	For if we need to return early
	li		r9, paramErr


	lwz		r16, Area.Flags(r31)
	lwz		r17,  0x0020(r31)
	rlwinm.	r16, r16,  0, 28, 28

	lisori	r16, 0xfffc13e0		; if bit 28 = 0
	beq		@use_other
	lisori	r16, 0xfff99be0		; if bit 28 = 1
@use_other

	and.	r16, r16, r17
	bne		ReturnFromCreateArea

	andi.	r16, r17,  0x1f
	cmpwi	cr1, r16,  0x0c
	beq		CreateArea_0x50
	blt		cr1, ReturnFromCreateArea

CreateArea_0x50
	bne		CreateArea_0x5c
	ori		r17, r17,  0x0c
	stw		r17,  0x0020(r31)

CreateArea_0x5c
	andi.	r16, r17,  0x1f
	li		r18, -0x01
	slw		r18, r18, r16
	stw		r18,  0x0078(r31)
	rlwinm.	r16, r17, 27, 27, 31
	bne		ReturnFromCreateArea
	addi	r16, r16,  0x0c
	li		r18, -0x01
	slw		r18, r18, r16
	stw		r18,  0x007c(r31)
	neg		r16, r18
	not		r19, r18
	stw		r16,  0x0068(r31)
	lwz		r16, Area.Length(r31)
	add		r16, r16, r19
	and.	r16, r16, r18
	stw		r16, Area.Length(r31)
	beq		ReturnFromCreateArea
	lwz		r18,  0x001c(r31)
	lis		r16, -0x01
	ori		r16, r16,  0xff10
	and.	r16, r16, r18
	bne		ReturnFromCreateArea
	lwz		r16,  0x0070(r31)
	li		r17,  0x200
	rlwimi	r17, r16,  0,  0, 19
	bl		major_0x10cb8 ; PTE r16/r17, control r18 // PTE r16/r17
	stw		r16,  0x0070(r31)
	stw		r17,  0x0074(r31)
	mr		r8, r31

	li		r9, Area.kIDClass
	bl		MakeID
	cmpwi	r8, 0
	beq		major_0x10320

	stw		r8, Area.ID(r31)
	mfsprg	r16, 0
	lwz		r17, -0x0008(r16)
	lwz		r18,  0x0060(r17)
	lwz		r30, Area.AddressSpacePtr(r17)
	stw		r18, Area.ProcessID(r31)
	lwz		r16, Area.AddressSpacePtr(r31)
	lwz		r17,  0x0000(r16)
	stw		r17, Area.AddressSpaceID(r31)
	lwz		r16,  0x0008(r30)
	rlwinm.	r16, r16,  0, 30, 30
	bne		major_0x10320_0x64
	lis		r16,  0x4152
	ori		r16, r16,  0x4541
	stw		r16, Area.Signature(r31)
	lwz		r17,  0x0020(r31)
	lwz		r16, Area.LogicalSeparation(r31)
	addi	r16, r16,  0xfff
	rlwinm	r16, r16,  0,  0, 19
	stw		r16, Area.LogicalSeparation(r31)
	rlwinm	r16, r17,  0, 17, 18
	cmplwi	cr7, r16,  0x6000
	rlwinm.	r16, r17,  0, 17, 17
	beq		cr7, CreateArea_0x150
	bne		CreateArea_0x150
	crset	cr7_gt
	crclr	cr7_lt

CreateArea_0x150
	rlwinm.	r16, r17,  0, 17, 18
	lwz		r18, Area.LogicalBase(r31)
	lwz		r19, Area.Length(r31)
	blt		cr7, CreateArea_0x16c
	bne		CreateArea_0x170
	li		r18,  0x00
	b		CreateArea_0x170

CreateArea_0x16c
	subf	r18, r19, r18

CreateArea_0x170
	lwz		r16,  0x0078(r31)
	and		r18, r18, r16
	stw		r18, Area.LogicalBase(r31)
	add		r16, r18, r19
	addi	r16, r16, -0x01
	stw		r16, Area.LogicalEnd(r31)


	;	Major hint here...

	_log	' CreateArea [ '
	mr		r8, r18
	bl		Printw
	mr		r8, r16
	bl		Printw
	_log	'] ID '


	lwz		r8, Area.ID(r31)
	mr		r8, r8
	bl		Printw


	bgt		cr7, CreateArea_0x1f4
	blt		cr7, CreateArea_0x218
	_log	'placed'
	b		CreateArea_0x234

CreateArea_0x1f4
	_log	'placed at or above'
	b		CreateArea_0x234

CreateArea_0x218
	_log	'placed below'

CreateArea_0x234
	lwz		r8, Area.AddressSpacePtr(r31)
	lwz		r16, Area.LogicalEnd(r31)
	lwz		r9, Area.LogicalBase(r31)
	cmplw	r9, r16
	bge		major_0x10320_0x64
	bl		FindAreaAbove
	mr		r30, r8
	lwz		r14, Area.LogicalBase(r31)
	lwz		r15, Area.LogicalEnd(r31)
	lwz		r16, Area.LogicalSeparation(r31)
	lwz		r17,  0x0024(r30)
	lwz		r18,  0x0028(r30)
	lwz		r19,  0x0030(r30)
	lwz		r21, Area.AddressSpacePtr(r31)
	cmpwi	r17, -0x01
	add		r8, r15, r16
	add		r9, r15, r19
	beq		CreateArea_0x2b8
	cmplw	r8, r17
	cmplw	cr1, r9, r17
	bge		CreateArea_0x28c
	blt		cr1, CreateArea_0x2b8

CreateArea_0x28c
	beq		cr7, major_0x10320_0x64
	_log	' ... bc search^n'
	bgt		cr7, CreateArea_0x34c
	b		CreateArea_0x31c

CreateArea_0x2b8
	addi	r21, r21,  0x20
	lwz		r20,  0x0060(r30)
	cmpw	r20, r21
	beq		CreateArea_0x39c
	addi	r20, r20, -0x54
	lwz		r17,  0x0024(r20)
	lwz		r18,  0x0028(r20)
	lwz		r19,  0x0030(r20)
	add		r8, r18, r16
	add		r9, r18, r19
	cmplw	r8, r14
	cmplw	cr1, r9, r14
	bge		CreateArea_0x2f0
	blt		cr1, CreateArea_0x374

CreateArea_0x2f0
	beq		cr7, major_0x10320_0x64
	_log	' ... ab search^n'
	bgt		cr7, CreateArea_0x34c
	b		CreateArea_0x31c

CreateArea_0x31c
	subf	r8, r19, r17
	subf	r9, r16, r17
	cmplw	r8, r9
	lwz		r21, Area.Length(r31)
	ble		CreateArea_0x334
	mr		r8, r9

CreateArea_0x334
	subf	r8, r21, r8
	cmplw	r8, r14
	addi	r18, r8,  0x01
	lwz		r19, Area.Length(r31)
	bge		major_0x10320_0x64
	b		CreateArea_0x170

CreateArea_0x34c
	add		r8, r18, r19
	add		r9, r18, r16
	lwz		r20,  0x0078(r31)
	cmplw	r8, r9
	neg		r21, r20
	bge		CreateArea_0x368
	mr		r8, r9

CreateArea_0x368
	add		r18, r8, r21
	lwz		r19, Area.Length(r31)
	b		CreateArea_0x170

CreateArea_0x374
	addi	r19, r31,  0x54
	addi	r20, r20,  0x54
	lwz		r16,  0x0000(r20)
	stw		r16,  0x0000(r19)
	lwz		r16,  0x0008(r20)
	stw		r16,  0x0008(r19)
	stw		r20,  0x000c(r19)
	stw		r19,  0x000c(r16)
	stw		r19,  0x0008(r20)
	b		CreateArea_0x3b8

CreateArea_0x39c
	addi	r19, r31,  0x54
	stw		r20,  0x0000(r19)
	InsertAsNext	r19, r20, scratch=r16

CreateArea_0x3b8
	addi	r16, r31,  0x90
	InitList	r16, 'fenc', scratch=r17
	lwz		r16,  0x0020(r31)
	lwz		r17, Area.Flags(r31)
	rlwinm.	r8, r16,  0, 16, 16
	bne		CreateArea_0x64c
	rlwinm.	r8, r17,  0, 25, 25
	bne		CreateArea_0x41c
	lwz		r8, Area.Length(r31)
	rlwinm	r8, r8, 22, 10, 29
	mr		r29, r8

;	r1 = kdp
;	r8 = size
	bl		PoolAllocClear
;	r8 = ptr

	cmpwi	r8,  0x00
	stw		r8,  0x0040(r31)
	beq		CreateArea_0x460
	lwz		r9, Area.Length(r31)
	srwi	r9, r9, 12
	bl		major_0x10284
	lwz		r17, Area.Flags(r31)
	ori		r17, r17,  0x10
	stw		r17, Area.Flags(r31)

CreateArea_0x41c
	lwz		r17, Area.Flags(r31)
	andi.	r8, r17,  0x88
	lwz		r8, Area.Length(r31)
	bne		CreateArea_0x45c
	rlwinm	r8, r8, 21, 11, 30
	mr		r29, r8

;	r1 = kdp
;	r8 = size
	bl		PoolAllocClear
;	r8 = ptr

	cmpwi	r8,  0x00
	stw		r8,  0x003c(r31)
	beq		CreateArea_0x460
	lwz		r9, Area.Length(r31)
	srwi	r9, r9, 12
	bl		major_0x102a8
	lwz		r16, Area.Flags(r31)
	ori		r16, r16,  0x01
	stw		r16, Area.Flags(r31)

CreateArea_0x45c
	b		CreateArea_0x64c

CreateArea_0x460
	cmpwi	r29,  0xfd8
	ble		major_0x10320_0x20

	_Lock			PSA.PoolLock, scratch1=r16, scratch2=r17

	lwz		r17, Area.Flags(r31)
	li		r27,  0x00
	rlwinm.	r8, r17,  0, 25, 25
	bne		CreateArea_0x4b4
	lwz		r27, Area.Length(r31)
	srwi	r27, r27, 12
	cmpwi	r27,  0x400
	ble		CreateArea_0x4ac
	ori		r17, r17,  0x20
	stw		r17, Area.Flags(r31)
	addi	r27, r27,  0x400

CreateArea_0x4ac
	addi	r27, r27,  0x3ff
	srwi	r27, r27, 10

CreateArea_0x4b4
	lwz		r8, Area.Flags(r31)
	li		r29,  0x00
	rlwinm.	r9, r8,  0, 28, 28
	bne		CreateArea_0x4e8
	lwz		r29, Area.Length(r31)
	srwi	r29, r29, 12
	cmpwi	r29,  0x800
	ble		CreateArea_0x4e0
	ori		r8, r8,  0x02
	stw		r8, Area.Flags(r31)
	addi	r29, r29,  0x800

CreateArea_0x4e0
	addi	r29, r29,  0x7ff
	srwi	r29, r29, 11

CreateArea_0x4e8
	lwz		r18, PSA.FreePageCount(r1)
	add.	r8, r27, r29
	ble		major_0x102c8
	cmpw	r8, r18
	bgt		major_0x102c8
	lwz		r16, PSA.FreePageCount(r1)
	lwz		r17, PSA.UnheldFreePageCount(r1)
	subf	r16, r8, r16
	subf	r17, r8, r17
	stw		r16, PSA.FreePageCount(r1)
	stw		r17, PSA.UnheldFreePageCount(r1)
	mr.		r18, r27
	beq		CreateArea_0x5a0
	lwz		r16, PSA.FreeList + LLL.Next(r1)
	RemoveFromList		r16, scratch1=r17, scratch2=r19
	addi	r18, r18, -0x01
	stw		r16,  0x0040(r31)
	cmpwi	r18,  0x00
	lwz		r17, PSA.FreeList + LLL.Next(r1)
	mr		r8, r16
	subi	r16, r16, 4
	bgt		CreateArea_0x564
	li		r9,  0x400
	bl		major_0x10284
	b		CreateArea_0x5a0

CreateArea_0x564
	RemoveFromList		r17, scratch1=r19, scratch2=r20
	addi	r18, r18, -0x01
	stwu	r17,  0x0004(r16)
	mr		r8, r17
	li		r9,  0x400
	bl		major_0x10284
	lwz		r17, PSA.FreeList + LLL.Next(r1)
	cmpwi	r18,  0x00
	bgt		CreateArea_0x564

CreateArea_0x5a0
	mr.		r18, r29
	beq		CreateArea_0x62c
	lwz		r16, PSA.FreeList + LLL.Next(r1)
	RemoveFromList		r16, scratch1=r17, scratch2=r19
	addi	r18, r18, -0x01
	stw		r16,  0x003c(r31)
	cmpwi	r18,  0x00
	lwz		r17, PSA.FreeList + LLL.Next(r1)
	mr		r8, r16
	subi	r16, r16, 4
	bgt		CreateArea_0x5f0
	li		r9,  0x800
	bl		major_0x102a8
	b		CreateArea_0x62c

CreateArea_0x5f0
	RemoveFromList		r17, scratch1=r19, scratch2=r20
	addi	r18, r18, -0x01
	stwu	r17,  0x0004(r16)
	mr		r8, r17
	li		r9,  0x800
	bl		major_0x102a8
	lwz		r17, PSA.FreeList + LLL.Next(r1)
	cmpwi	r18,  0x00
	bgt		CreateArea_0x5f0

CreateArea_0x62c
	_AssertAndRelease	PSA.PoolLock, scratch=r16

CreateArea_0x64c
	lwz		r16, Area.Flags(r31)
	rlwinm.	r8, r16,  0, 28, 28
	beq		CreateArea_0x67c
	lwz		r16,  0x0044(r31)
	addi	r17, r31,  0x44
	stw		r16,  0x0000(r17)
	InsertAsPrev	r17, r16, scratch=r18
	b		major_0x10320_0x94

CreateArea_0x67c
	addi	r16, r31,  0x44
	InitList	r16, 'AKA ', scratch=r17
	b		major_0x10320_0x94



major_0x10284	;	OUTSIDE REFERER
	subi	r8, r8, 4
	addi	r9, r9, -0x01
	lwz		r20,  0x0074(r31)
	ori		r20, r20,  0x200

major_0x10284_0x10
	cmpwi	r9, noErr
	stwu	r20,  0x0004(r8)
	addi	r9, r9, -0x01
	bgt		major_0x10284_0x10
	blr



major_0x102a8	;	OUTSIDE REFERER
	addi	r8, r8, -0x02
	addi	r9, r9, -0x01
	li		r20,  0x7fff

major_0x102a8_0xc
	cmpwi	r9, noErr
	sthu	r20,  0x0002(r8)
	addi	r9, r9, -0x01
	bgt		major_0x102a8_0xc
	blr



major_0x102c8	;	OUTSIDE REFERER
	_AssertAndRelease	PSA.PoolLock, scratch=r16
	addi	r30, r8,  0x08
	lwz		r8, PSA.AgerID(r1)
 	bl		LookupID
	cmpwi	r9, Notification.kIDClass

	mr		r26, r8
	bne		major_0x10320_0x20
	li		r8,  0x02
	stw		r8,  0x0010(r26)
	stw		r30,  0x0014(r26)
	li		r29,  0x00
	stw		r29,  0x0018(r26)
	mr		r30, r26
	bl		CauseNotification
	b		major_0x10320_0x20



major_0x10320	;	OUTSIDE REFERER
	mr		r8, r31
	li		r9, -29294
	b		ReturnFromCreateArea

	;	Dead code:
	lwz		r8, Area.ID(r31)
	bl		DeleteID
	mr		r8, r31
	li		r9, kMPInvalidIDErr
	b		ReturnFromCreateArea

major_0x10320_0x20	;	OUTSIDE REFERER
	addi	r19, r31,  0x54
	RemoveFromList		r19, scratch1=r16, scratch2=r17
	lwz		r16, Area.Flags(r31)
	lwz		r8,  0x0040(r31)
	rlwinm.	r16, r16,  0, 25, 25
	bne		major_0x10320_0x58
	cmpwi	r8,  0x00
	bnel	PoolFree

major_0x10320_0x58
	lwz		r8,  0x003c(r31)
	cmpwi	r8,  0x00
	bnel	PoolFree

major_0x10320_0x64	;	OUTSIDE REFERER
	_log	' ... skipped^n'
	lwz		r8, Area.ID(r31)
	bl		DeleteID
	mr		r8, r31
	li		r9, kMPInsufficientResourcesErr
	b		ReturnFromCreateArea

major_0x10320_0x94	;	OUTSIDE REFERER
	_log	' ... created^n'
	mr		r8, r31
	li		r9,  0x00



ReturnFromCreateArea
	mfsprg	r16, 0
	lwz		r17, EWA.CreateAreaSavedLR(r16)
	mtlr	r17
	lmw		r25, EWA.CreateAreaSavedR25(r16)
	blr



;	ARG		AddressSpace *r8, 
;	RET		Area *r8

FindAreaAbove	;	OUTSIDE REFERER
	lwz		r8, AddressSpace.AreaList + LLL.Next(r8)

@loop
	subi	r8, r8, Area.LLL

	;	Return an area such that:
	;		max(Area.LogicalBase, Area.LogicalEnd) >= r9
	lwz		r16, Area.LogicalBase(r8)
	lwz		r17, Area.LogicalEnd(r8)
	cmplw	r16, r9
	cmplw	cr1, r17, r9
	bgelr
	bgelr	cr1

	;	Iterate over linked list
	lwz		r8, Area.LLL + LLL.Next(r8)
	b		@loop



#     # ######   #####                                       #                              #                         
##   ## #     # #     # #####  ######   ##   ##### ######   # #   #      #   ##    ####    # #   #####  ######   ##   
# # # # #     # #       #    # #       #  #    #   #       #   #  #      #  #  #  #       #   #  #    # #       #  #  
#  #  # ######  #       #    # #####  #    #   #   #####  #     # #      # #    #  ####  #     # #    # #####  #    # 
#     # #       #       #####  #      ######   #   #      ####### #      # ######      # ####### #####  #      ###### 
#     # #       #     # #   #  #      #    #   #   #      #     # #      # #    # #    # #     # #   #  #      #    # 
#     # #        #####  #    # ###### #    #   #   ###### #     # ###### # #    #  ####  #     # #    # ###### #    # 

;	This MP call does most of the work for the same-named MPLibrary
;	function. An "alias" Area is created from a template. This code is very
;	similar to regular MPCreateArea above, so differences are commented.

;	ARG		AreaID r3										; Alias-specific
;			long r4 PTEConfig
;			long r5 length
;			long r6 LogicalSeparation
;			long r7 flagsAndMinAlign
;			char *r8 LogicalBase
;			long r9 unknown									; Alias-specific
;	RET		r3 OSErr
;			char *r8 LogicalBase
;			AreaID r10										; Alias-specific

	DeclareMPCall	73, MPCreateAliasArea

MPCreateAliasArea

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass
	bne		ReleaseAndReturnMPCallInvalidIDErr

	;	Confirm that the template Area is not itself an alias
	mr		r30, r8
	lwz		r16, Area.Flags(r30)
	rlwinm.	r8, r16, 0, Area.kAliasFlag, Area.kAliasFlag
	bne		ReleaseAndReturnParamErrFromMPCall

	;	Allocate the new Area
	li		r8, Area.Size
	bl		PoolAllocClear
	mr.		r31, r8
	beq		ReleaseAndScrambleMPCall

	;	Populate
	mfsprg	r28, 0
	lwz		r8, EWA.PA_CurAddressSpace(r28)
	stw		r8, Area.AddressSpacePtr(r31)

	stw		r3, Area.ParentAreaID(r31)						; Alias-specific

	stw		r30, Area.AliasLLL + LLL.Freeform(r31)			; Alias-specific

	stw		r4, Area.PTEConfig(r31)

	stw		r5, Area.Length(r31)

	lwz		r8, ContextBlock.r6(r6)
	stw		r8, Area.LogicalSeparation(r31)

	lwz		r8, ContextBlock.r7(r6)
	stw		r8, Area.FlagsAndMinAlign(r31)

	lwz		r8, ContextBlock.r8(r6)
	stw		r8, Area.LogicalBase(r31)

	lwz		r8, ContextBlock.r9(r6)							; Alias-specific
	stw		r8,  0x0080(r31)

	li		r8, 1 << (31 - Area.kAliasFlag)					; Alias-specific
	stw		r8, Area.Flags(r31)

	;	"Create" the area (everything after here is identical to MPCreateArea)
	mr		r8, r31
	bl		CreateArea

	_AssertAndRelease	PSA.SchLock, scratch=r16

	mr.		r3, r9
	bne		@error

	;	CreateArea returned successfully
	lwz		r8, Area.LogicalBase(r31)
	stw		r8, ContextBlock.r8(r6)

	lwz		r8, Area.ID(r31)
	stw		r8, ContextBlock.r10(r6)						; Alias-specific

	b		CommonMPCallReturnPath

	;	...or not
@error
	bl		PoolFree
	b		CommonMPCallReturnPath



#     # ######  ######                                       #                         
##   ## #     # #     # ###### #      ###### ##### ######   # #   #####  ######   ##   
# # # # #     # #     # #      #      #        #   #       #   #  #    # #       #  #  
#  #  # ######  #     # #####  #      #####    #   #####  #     # #    # #####  #    # 
#     # #       #     # #      #      #        #   #      ####### #####  #      ###### 
#     # #       #     # #      #      #        #   #      #     # #   #  #      #    # 
#     # #       ######  ###### ###### ######   #   ###### #     # #    # ###### #    # 

;	Delete an Area: the eponymous MPLibrary function is a simple wrapper

;	1. Only works on unprivileged Areas with no mapped pages.
;	2. Remove from parent address space.
;	3. Remove from template Area's alias list if applicable.
;	4. Delete the "PageMap" array if present.
;	5. Delete the "Fault Counter" array if present.
;	6. Delete the structure from the pool.

;	ARG		AreaID r3
;	RET		OSErr r3

	DeclareMPCall	74, MPDeleteArea

MPDeleteArea

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	;	Look up and validate
	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass
	bne		ReleaseAndReturnMPCallInvalidIDErr
	mr		r31, r8

	;	If pages are still mapped in, fail with OOM
	;	If area is privileged, fail with privileged
	lwz		r17, Area.BytesMapped(r31)
	lwz		r29, Area.Flags(r31)
	cmpwi	cr1, r17, 0
	rlwinm.	r8, r29, 0, Area.kPrivilegedFlag, Area.kPrivilegedFlag
	bne		cr1, ReleaseAndReturnMPCallOOM
	bne		ReleaseAndReturnMPCallPrivilegedErr

	;	If is alias area and is not at back of queue (???), fail with OOM
	rlwinm.	r8, r29, 0, Area.kAliasFlag, Area.kAliasFlag
	lwz		r16, Area.AliasLLL + LLL.Next(r31)
	bne		@dont_check_for_nonempty_alias
	addi	r17, r31, Area.AliasLLL
	cmpw	r16, r17
	bne		ReleaseAndReturnMPCallOOM
@dont_check_for_nonempty_alias

	;	HTAB lock wraps around all Address Space structures?

	_Lock			PSA.HTABLock, scratch1=r18, scratch2=r9

	;	Remove from parent address space
	addi	r16, r31, Area.LLL
	RemoveFromList	r16, scratch1=r17, scratch2=r18

	;	Remove from template area's list of aliases, if necessary
	rlwinm.	r8, r29, 0, Area.kAliasFlag, Area.kAliasFlag
	addi	r16, r31, Area.AliasLLL
	beq		@not_alias_so_dont_remove_from_alias_list
	RemoveFromList	r16, scratch1=r17, scratch2=r18
@not_alias_so_dont_remove_from_alias_list

	_AssertAndRelease	PSA.HTABLock, scratch=r18


	;	DELETE PAGEMAP (array of [array of] per-page data)
	;	There are a few cases here...

	lwz		r8, Area.PageMapArrayPtr(r31)
	rlwinm.	r16, r29, 0, Area.kDontOwnPageMapArray, Area.kDontOwnPageMapArray
	cmpwi	cr1, r8, 0
	bne		@no_pagemap
	rlwinm.	r16, r29, 0, Area.kPageMapArrayInPool, Area.kPageMapArrayInPool
	beq		cr1, @no_pagemap
	bne		@pagemap_in_pool


	;	If PageMap occupies whole pages then return those pages
	;	directly to the free list without bothering the pool

	;	(Pool lock still protects free list)
	_Lock			PSA.PoolLock, scratch1=r18, scratch2=r9

	rlwinm.	r16, r29, 0, Area.kPageMapArrayIs2D, Area.kPageMapArrayIs2D
	beq		@pagemap_is_1d


	;	CASE: 2D array, all in whole pages

	;	r19 := size of ptr array in primary page
	lwz		r19, Area.Length(r31)
	mr		r20, r8
	srwi	r19, r19, 12
	addi	r19, r19, 0x3ff
	srwi	r19, r19, 10
	slwi	r19, r19, 2

	;	Free every second-level page
	subi	r19, r19, 4
@2d_pagemap_delete_loop
	lwzx	r8, r19, r20
	bl		FreePageListPush ; PhysicalPage *r8
	cmpwi	r19, 0
	subi	r19, r19, 4
	bgt		@2d_pagemap_delete_loop

	mr		r8, r20


	;	COMMON CASE: single first-level page of 2D or 1D-in-whole-page case

@pagemap_is_1d
	bl		FreePageListPush ; PhysicalPage *r8

	_AssertAndRelease	PSA.PoolLock, scratch=r18

	b		@pagemap_deleted


	;	CASE: 1D array in pool block (not whole page)

@pagemap_in_pool
	bl		PoolFree


@pagemap_deleted
@no_pagemap


	;	DELETE FAULT COUNTER ARRAY
	;	Again, the code to manage the cases is tricky.

	lwz		r8, Area.FaultCtrArrayPtr(r31)
	rlwinm.	r16, r29, 0, Area.kFaultCtrArrayInPool, Area.kFaultCtrArrayInPool
	cmpwi	cr1, r8, 0
	beq		cr1, @no_faultctr
	bne		@faultctr_in_pool


	;	Whole-page cases require us to get the Pool lock manually (for free list)
	_Lock			PSA.PoolLock, scratch1=r18, scratch2=r9

	rlwinm.	r16, r29, 0, Area.kFaultCtrArrayIs2D, Area.kFaultCtrArrayIs2D
	beq		@faultctr_is_1d


	;	CASE: 2D array, all in whole pages

	;	Once again, r19 = the size of the primary array
	lwz		r19, Area.Length(r31)
	mr		r20, r8
	srwi	r19, r19, 12
	addi	r19, r19, 0x7ff
	srwi	r19, r19, 11
	slwi	r19, r19, 2

	;	Free every second-level page
	subi	r19, r19, 4
@2d_faultctr_delete_loop
	lwzx	r8, r19, r20
	bl		FreePageListPush ; PhysicalPage *r8
	cmpwi	r19, 0
	subi	r19, r19, 4
	bgt		@2d_faultctr_delete_loop

	mr		r8, r20


	;	COMMON CASE: single first-level page of 2D or 1D-in-whole-page case

@faultctr_is_1d
	bl		FreePageListPush ; PhysicalPage *r8

	_AssertAndRelease	PSA.PoolLock, scratch=r18

	b		@faultctr_deleted


	;	CASE: 1D array in pool block (not whole page)

@faultctr_in_pool
	bl		PoolFree


@faultctr_deleted
@no_faultctr


	;	Delete the struct from the pool
	lwz		r8, Area.ID(r31)
	bl		DeleteID
	mr		r8, r31
	bl		PoolFree


	;	Return noErr
	b		ReleaseAndReturnZeroFromMPCall



#     # ######   #####                  #                          #####                  
##   ## #     # #     # ###### #####   # #   #####  ######   ##   #     # # ###### ###### 
# # # # #     # #       #        #    #   #  #    # #       #  #  #       #     #  #      
#  #  # ######   #####  #####    #   #     # #    # #####  #    #  #####  #    #   #####  
#     # #             # #        #   ####### #####  #      ######       # #   #    #      
#     # #       #     # #        #   #     # #   #  #      #    # #     # #  #     #      
#     # #        #####  ######   #   #     # #    # ###### #    #  #####  # ###### ###### 

;	ARG		MPAreaID r3, flag_24_means_change_left_side r4

;	Straight MPLibrary wrapper: no
;	In Universal Interfaces: no

	DeclareMPCall	75, MPSetAreaSize

MPSetAreaSize

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass
	mr		r31, r8
	bne		ReleaseAndReturnMPCallInvalidIDErr

	;	Chase Daniel about this field!
	lwz		r16, Area.FlagsAndMinAlign(r31)
	rlwinm.	r8, r16, 0, 16, 16
	bne		ReleaseAndReturnMPCallOOM

	lwz		r18, Area.DefaultAlignmentMask(r31)
	lwz		r17, Area.Length(r31)
	and.	r5, r5, r18
	and		r17, r17, r18
	ble		ReleaseAndReturnParamErrFromMPCall


	;	DECIDE: MAKE BIGGER OR MAKE SMALLER?

	subf.	r27, r17, r5							; r27 = how much space to add
	beq		ReleaseAndReturnZeroFromMPCall			; area is already this size (ignoring change)
	bgt		@SHRINK_AREA							; not actually allowed


;EXPAND AREA

	rlwinm.	r8, r4,  0, 24, 24
	lwz		r28, Area.LogicalBase(r31)
	lwz		r29, Area.LogicalEnd(r31)
	bne		@expand_downwards

;expand upwards ; (replace LogicalBase with new LogicalEnd)
	add		r28, r27, r29
	addi	r28, r28, 1
	b		@endif

@expand_downwards ; (replace LogicalEnd with new LogicalBase)
	subf	r29, r27, r28
	subi	r29, r29, 1
@endif


	_Lock			PSA.PoolLock, scratch1=r14, scratch2=r15
	_Lock			PSA.HTABLock, scratch1=r14, scratch2=r15


	;	Free pages from LogicalBase to LogicalEnd, flushing PTEs that might conflict (a million iterations???)

	lwz		r27, Area.PageSize(r31)

@freelist_loop
	mr		r8, r28
	bl		SpaceGetPagePLE ; LogicalPage *r8, Area *r31 // PLE *r30, notfound cr0.eq
	beq		SpacePanicIsland

	bl		GetPTEFromPLE ; PLE *r30 // PTE r16/r17, PTE *r18, PTEflags cr0, PLEflags cr5-7

	bc		BO_IF_NOT, Area.kPLEFlagHasPhysPage, @there_is_no_page_to_free

	bcl		BO_IF, Area.kPLEFlagIsInHTAB, InvalPTE ; page *r8, PTE r16/r17, PTE *r18, PLE *r30 // PLEflags cr5-7
	bcl		BO_IF, Area.kPLEFlagIsInHTAB, DeletePTE ; PTE *r18, PLE *r30

	;	Unset PLE bit kPLEFlagHasPhysPage and free the physical page
	lwz		r17, 0(r30)
	_bclr	r17, r17, Area.kPLEFlagHasPhysPage
	rlwinm	r8, r17, 0, 0xfffff000
	stw		r17, 0(r30)
	bl		FreePageListPush ; PhysicalPage *r8

@there_is_no_page_to_free

	add		r28, r28, r27
	cmplw	r28, r29
	ble		@freelist_loop



	rlwinm.	r8, r4,  0, 24, 24
	lwz		r28, Area.LogicalBase(r31)
	beq		@_138

	lwz		r27,  0x0068(r31)
	add		r29, r29, r27

@_100
	mr		r8, r28
	bl		SpaceGetPagePLE ; LogicalPage *r8, Area *r31 // PLE *r30, notfound cr0.eq
	beq		SpacePanicIsland
	mr		r26, r30
	mr		r8, r29
	bl		SpaceGetPagePLE ; LogicalPage *r8, Area *r31 // PLE *r30, notfound cr0.eq
	beq		SpacePanicIsland
	lwz		r17,  0x0000(r30)
	stw		r17,  0x0000(r26)
	lwz		r16, Area.LogicalEnd(r31)
	add		r28, r28, r27
	add		r29, r29, r27
	cmplw	r29, r16
	ble		@_100

@_138

	_AssertAndRelease	PSA.HTABLock, scratch=r8


	lwz		r16, Area.Flags(r31)
	rlwinm.	r8, r16,  0, 25, 25
	bne		@_16c

	rlwinm.	r8, r16,  0, 27, 27
	bne		@_16c


@_16c
	_AssertAndRelease	PSA.PoolLock, scratch=r8
	b		@_190

@_190
	rlwinm.	r8, r4,  0, 24, 24
	lwz		r16, Area.LogicalBase(r31)
	bne		@_1b0
	add		r17, r16, r5
	addi	r17, r17, -0x01
	stw		r5, Area.Length(r31)
	stw		r17, Area.LogicalEnd(r31)

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall

@_1b0
	lwz		r17, Area.LogicalEnd(r31)
	subf	r16, r5, r17
	stw		r5, Area.Length(r31)
	addi	r16, r16,  0x01
	stw		r16, Area.LogicalBase(r31)

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall


@SHRINK_AREA

	rlwinm.	r8, r4,  0, 24, 24
	lwz		r28, Area.LogicalBase(r31)
	lwz		r29, Area.LogicalEnd(r31)
	bne		ReleaseAndMPCallWasBad

	add		r28, r27, r29
	addi	r28, r28,  0x01

	b		@_1ec
	;	Dead code:
	subf	r29, r27, r28
	subi	r29, r29, 1
@_1ec

	b		ReleaseAndMPCallWasBad



#     # ######   #####                #####                ######                          #                                       
##   ## #     # #     # ###### ##### #     # #    # #####  #     #   ##    ####  ######   # #    ####   ####  ######  ####   ####  
# # # # #     # #       #        #   #       #    # #    # #     #  #  #  #    # #       #   #  #    # #    # #      #      #      
#  #  # ######   #####  #####    #    #####  #    # #####  ######  #    # #      #####  #     # #      #      #####   ####   ####  
#     # #             # #        #         # #    # #    # #       ###### #  ### #      ####### #      #      #           #      # 
#     # #       #     # #        #   #     # #    # #    # #       #    # #    # #      #     # #    # #    # #      #    # #    # 
#     # #        #####  ######   #    #####   ####  #####  #       #    #  ####  ###### #     #  ####   ####  ######  ####   ####  

;	Straight MPLibrary wrapper: almost
;	In Universal Interfaces: no

	DeclareMPCall	130, MPSetSubPageAccess

MPSetSubPageAccess

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass

	bne		ReleaseAndReturnMPCallInvalidIDErr
	mr		r31, r8
	lis		r16, -0x01
	ori		r16, r16,  0xfff8
	lwz		r17,  0x0020(r31)
	and.	r16, r16, r4
	bne		ReleaseAndReturnParamErrFromMPCall
	rlwinm.	r8, r17,  0, 16, 16
	bne		ReleaseAndReturnParamErrFromMPCall
	mr		r29, r5
	lwz		r18,  0x0134(r6)
	lwz		r19,  0x0068(r31)
	lwz		r16, Area.LogicalBase(r31)
	cmplw	r18, r19
	add		r28, r18, r29
	bge		ReleaseAndReturnParamErrFromMPCall
	lwz		r17,  0x007c(r31)
	addi	r28, r28, -0x01
	lwz		r18,  0x0020(r31)
	lwz		r19, Area.LogicalEnd(r31)
	cmplw	cr1, r29, r16
	cmplw	cr2, r28, r19
	blt		cr1, ReleaseAndReturnParamErrFromMPCall
	bgt		cr2, ReleaseAndReturnParamErrFromMPCall
	xor		r8, r28, r29
	rlwinm.	r8, r8,  0,  0, 19
	bne		ReleaseAndReturnParamErrFromMPCall

	_Lock			PSA.HTABLock, scratch1=r14, scratch2=r15

	mr		r8, r29
	bl		SpaceGetPagePLE ; LogicalPage *r8, Area *r31 // PLE *r30, notfound cr0.eq
	_AssertAndRelease	PSA.HTABLock, scratch=r14
	beq		SpacePanicIsland
	rlwinm	r8, r16,  0, 29, 30
	lwz		r16,  0x0000(r30)
	cmpwi	cr7, r8,  0x04
	beq		cr7, ReleaseAndReturnParamErrFromMPCall
	lwz		r16,  0x0098(r31)

MPCall_130_0xe8
	addi	r17, r31,  0x90
	cmpw	r16, r17
	addi	r17, r16,  0x14
	beq		MPCall_130_0x11c
	lwz		r8,  0x0010(r16)
	cmplwi	r8,  0x1f8
	add		r9, r8, r17
	blt		MPCall_130_0x110
	lwz		r16,  0x0008(r16)
	b		MPCall_130_0xe8

MPCall_130_0x110
	addi	r8, r8,  0x08
	addi	r9, r9,  0x08
	b		MPCall_130_0x15c

MPCall_130_0x11c
	li		r8,  0x214

;	r1 = kdp
;	r8 = size
	bl		PoolAllocClear
;	r8 = ptr

	mr.		r16, r8
	beq		ReleaseAndScrambleMPCall
	addi	r18, r31,  0x90
	lis		r17,  0x4645
	ori		r17, r17,  0x4e43
	stw		r17,  0x0004(r16)
	stw		r18,  0x0000(r16)
	InsertAsPrev	r16, r18, scratch=r19
	li		r8,  0x00
	addi	r9, r16,  0x14

MPCall_130_0x15c
	stw		r8,  0x0010(r16)
	stw		r29,  0x0000(r9)
	stw		r28,  0x0004(r9)

	_Lock			PSA.HTABLock, scratch1=r14, scratch2=r15

	mr		r8, r29
	bl		SpaceGetPagePLE ; LogicalPage *r8, Area *r31 // PLE *r30, notfound cr0.eq
	beq		SpacePanicIsland

	bl		GetPTEFromPLE ; PLE *r30 // PTE r16/r17, PTE *r18, PTEflags cr0, PLEflags cr5-7

	bc		BO_IF_NOT, Area.kPLEFlagHasPhysPage, MPCall_130_0x19c

	bcl		BO_IF, Area.kPLEFlagIsInHTAB, InvalPTE ; page *r8, PTE r16/r17, PTE *r18, PLE *r30 // PLEflags cr5-7
	bcl		BO_IF, Area.kPLEFlagIsInHTAB, DeletePTE ; PTE *r18, PLE *r30

MPCall_130_0x19c
	lwz		r17,  0x0000(r30)
	li		r16,  0x06
	rlwimi	r17, r16,  0, 29, 30
	stw		r17,  0x0000(r30)
	_AssertAndRelease	PSA.HTABLock, scratch=r14

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall



#     # ######   #####                  #                            #                                       
##   ## #     # #     # ###### #####   # #   #####  ######   ##     # #    ####   ####  ######  ####   ####  
# # # # #     # #       #        #    #   #  #    # #       #  #   #   #  #    # #    # #      #      #      
#  #  # ######   #####  #####    #   #     # #    # #####  #    # #     # #      #      #####   ####   ####  
#     # #             # #        #   ####### #####  #      ###### ####### #      #      #           #      # 
#     # #       #     # #        #   #     # #   #  #      #    # #     # #    # #    # #      #    # #    # 
#     # #        #####  ######   #   #     # #    # ###### #    # #     #  ####   ####  ######  ####   ####  

;	ARG		MPAreaID r3, bits_to_set r4, bits_to_unset r5, start r6, len r7
;	RET		OSStatus r3

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: no

	DeclareMPCall	76, MPSetAreaAccess

MPSetAreaAccess

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass
	bne		ReleaseAndReturnMPCallInvalidIDErr
	mr		r31, r8

	;	Fail if any bits other than these are set in r4
	lisori	r16, ~%11101111
	and.	r16, r16, r4
	bne		ReleaseAndReturnParamErrFromMPCall

	;	Or in r5
	lisori	r16, ~%11101111
	and.	r16, r16, r5
	bne		ReleaseAndReturnParamErrFromMPCall

	;	Get more args
	lwz		r29, ContextBlock.r6(r6)
	lwz		r18, ContextBlock.r7(r6)

	;	Figure out whether the Area covers the specified range
	lwz		r16, Area.LogicalBase(r31)
	add		r28, r18, r29
	lwz		r17, Area.DefaultAlignmentMask(r31) ; unused?
	subi	r28, r28, 1
	lwz		r18, Area.FlagsAndMinAlign(r31)
	lwz		r19, Area.LogicalEnd(r31)

	;	Check that range lies within Area (cr1/2).
	;	Also, two cases depending on FlagsAndMinAlign bit 16
	rlwinm.	r8, r18, 0, 16, 16
	cmplw	cr1, r29, r16
	cmplw	cr2, r28, r19
	blt		cr1, ReleaseAndReturnParamErrFromMPCall
	bgt		cr2, ReleaseAndReturnParamErrFromMPCall
	bne		@BIT_16_SET


;BIT 16 CLEAR

	_Lock			PSA.HTABLock, scratch1=r14, scratch2=r15

@pageloop
	mr		r8, r29
	bl		SpaceGetPagePLE ; LogicalPage *r8, Area *r31 // PLE *r30, notfound cr0.eq
	beq		SpacePanicIsland

	bl		GetPTEFromPLE ; PLE *r30 // PTE r16/r17, PTE *r18, PTEflags cr0, PLEflags cr5-7

	bc		BO_IF_NOT, Area.kPLEFlagHasPhysPage, @no_physical_page
	bcl		BO_IF, Area.kPLEFlagIsInHTAB, InvalPTE ; page *r8, PTE r16/r17, PTE *r18, PLE *r30 // PLEflags cr5-7
	bcl		BO_IF, Area.kPLEFlagIsInHTAB, DeletePTE ; PTE *r18, PLE *r30
@no_physical_page

	lwz		r17, 0(r30)
	bl		major_0x10d38

	and		r8, r4, r5
	orc		r9, r4, r5
	or		r18, r18, r8
	and		r18, r18, r9

	lwz		r17, 0(r30)

	rlwinm.	r8, r18,  0, 26, 26
	bc		BO_IF_NOT, 31, @118
	bgt		cr6, @118
	beq		@118

	;	Remove the page in question from the data cache
	rlwinm	r9, r17, 0, 0xFFFFF000
	lwz		r8, Area.PageSize(r31)
@dcache_flush_loop
	subi	r8, r8, 32
	dcbf	r8, r9
	cmpwi	r8, 0
	bgt		@dcache_flush_loop
	sync

	;	Also from the inst cache
	lwz		r8, Area.PageSize(r31)
@icache_flush_loop
	subi	r8, r8, 32
	icbi	r8, r9
	cmpwi	r8, 0
	bgt		@icache_flush_loop
	isync

@118
	bl		major_0x10cb8 ; PTE r16/r17, control r18 // PTE r16/r17

	lwz		r19, Area.PageSize(r31)
	stw		r17, 0(r30)
	add		r29, r29, r19
	subf.	r8, r29, r28
	bge		@pageloop
	_AssertAndRelease	PSA.HTABLock, scratch=r14

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall

@BIT_16_SET

	bne		cr1, ReleaseAndReturnParamErrFromMPCall
	lwz		r18,  0x001c(r31)
	and		r8, r4, r5
	orc		r9, r4, r5
	or		r18, r18, r8
	and		r18, r18, r9
	stw		r18,  0x001c(r31)
	lwz		r16,  0x0070(r31)
	lwz		r17,  0x0074(r31)
	bl		major_0x10cb8 ; PTE r16/r17, control r18 // PTE r16/r17
	stw		r16,  0x0070(r31)
	stw		r17,  0x0074(r31)

	_Lock			PSA.HTABLock, scratch1=r14, scratch2=r15

	lwz		r27,  0x0068(r31)
	mr		r28, r19

@1a4
	mr		r8, r29
	lwz		r9, Area.AddressSpacePtr(r31)
	bl		SpaceL2PIgnoringBATs ; LogicalPage *r8, MPAddressSpace *r9 // PhysicalPage *r17
	beq		@1bc
	bl		InvalPTE ; page *r8, PTE r16/r17, PTE *r18, PLE *r30 // PLEflags cr5-7
	bl		DeletePTE ; PTE *r18, PLE *r30

@1bc
	add		r29, r29, r27
	subf.	r8, r29, r28
	bge		@1a4
	_AssertAndRelease	PSA.HTABLock, scratch=r14

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall



;	ARG		PTE r16, PTE r17, control r18
;	RET		PTE r16, PTE r17
;	CLOB	CR


major_0x10cb8 ; PTE r16/r17, control r18 // PTE r16/r17

	rlwinm	r16, r16,  0, 0xFFFFFF87		;	fill these in again...
	rlwinm	r17, r17,  0, 0xFFFFFF1F		;	
	rlwinm	r16, r16,  0, 0xFFFFFFFC		;	clear
	rlwinm	r17, r17,  0, 0xFFFFFFF9		;	


	;	Load control argument into condition register
	;	Note: this is a pretty expensive operation, not in hot path

	mtcr	r18


	bge		cr6, @80_not_set				;	if(control & 0x80) {
	ori		r17, r17, 0x80					;		PTE2 |= 0x80; //set referenced bit
	ori		r16, r16, 0x08					;		PTE1 |= 0x08; //set guard bit
@80_not_set									;	}


	ble		cr6, @40_not_set				;	if(control & 0x40) {
	ori		r16, r16, 0x40					;		PTE1 |= 0x40; //set change bit
	b		@40_endif						;	} else {
@40_not_set
	ori		r17, r17, 0x20					;		PTE2 |= 0x20; //set W bit
@40_endif									;	}


	bne		cr6, @20_not_set				;	if(control & 0x20) {
	ori		r17, r17,  0x40					;		PTE2 |= 0x40; //set change bit
	ori		r16, r16,  0x20					;		PTE1 |= 0x20; //set W bit
@20_not_set									;	}


	ble		cr7, @04_not_set				;	if(control & 0x04) {
@04_not_set									;	}


	bge		cr7, @08_not_set				;	if(control & 0x08) {
	ori		r17, r17, 0x06					;		PTE2 |= 0x06; //set leftmost protection bit and reserved bit
	ori		r16, r16, 0x01					;		PTE1 |= 0x01; //set rightmost protection bit
	b		@block_endif					;	}
@08_not_set
	bne		cr7, @02_not_set				;	else if(control & 0x02) {
	ori		r17, r17, 0x00					;		PTE2 |= 0x00; //useless instruction?
	ori		r16, r16, 0x02					;		PTE1 |= 0x02; //set second protection bit
	b		@block_endif					;	}
@02_not_set
	bc		BO_IF_NOT, 31, @01_not_set				;	else if(control & 0x01) {
	ori		r17, r17, 0x04					;		PTE2 |= 0x04; //set reserved bit.
	ori		r16, r16, 0x03					;		PTE1 |= 0x03: //set both protection bits
	b		@block_endif					;	}
@01_not_set									;	else {
	ori		r17, r17, 0x02					;		PTE2 |= 0x02; //set second protection bit
	ori		r16, r16, 0x00					;		PTE1 |= 0x00; //useless instruction?
@block_endif								;	}


	ori		r16, r16,  0x10					;	PTE1 |= 0x10; //set M bit


	blr										;	return (PTE1, PTE2);



major_0x10d38 ; PLE r17

	andi.	r16, r17, %110

	li		r18, 0

	cmpwi	cr0, r16, %010
	cmpwi	cr1, r16, %110
	beq		cr0, @disconcordant

	li		r18, %100
	andi.	r16, r17, %100
	ori		r18, r18, %001					; may as well have set both P bits in r8?
	bne		@disconcordant
	ori		r18, r18, %010
@disconcordant

	bne		cr1, major_0x10d38_0x30
	ori		r18, r18, 0x8

major_0x10d38_0x30
	andi.	r16, r17, 0x20
	bne		major_0x10d38_0x3c
	ori		r18, r18, 0x40

major_0x10d38_0x3c
	andi.	r16, r17, 0x40
	beq		major_0x10d38_0x48
	ori		r18, r18, 0x20

major_0x10d38_0x48
	andi.	r16, r17, 0x80
	beq		major_0x10d38_0x54
	ori		r18, r18, 0x80

major_0x10d38_0x54
	blr



major_0x10d38_0x58	;	OUTSIDE REFERER
	andi.	r16, r17,  0x03
	li		r18,  0x04
	cmpwi	cr1, r16,  0x01
	beq		major_0x10d38_0x78
	andi.	r16, r17,  0x01
	ori		r18, r18,  0x01
	bne		major_0x10d38_0x78
	ori		r18, r18,  0x02

major_0x10d38_0x78
	bne		cr1, major_0x10d38_0x80
	ori		r18, r18,  0x08

major_0x10d38_0x80
	andi.	r16, r17,  0x40
	beq		major_0x10d38_0x8c
	ori		r18, r18,  0x40

major_0x10d38_0x8c
	andi.	r16, r17,  0x20
	beq		major_0x10d38_0x98
	ori		r18, r18,  0x20

major_0x10d38_0x98
	andi.	r16, r17,  0x08
	beq		major_0x10d38_0xa4
	ori		r18, r18,  0x80

major_0x10d38_0xa4
	blr



#     # ######   #####                  #                            #                                       
##   ## #     # #     # ###### #####   # #   #####  ######   ##     # #    ####   ####  ######  ####   ####  
# # # # #     # #       #        #    #   #  #    # #       #  #   #   #  #    # #    # #      #      #      
#  #  # ######  #  #### #####    #   #     # #    # #####  #    # #     # #      #      #####   ####   ####  
#     # #       #     # #        #   ####### #####  #      ###### ####### #      #      #           #      # 
#     # #       #     # #        #   #     # #   #  #      #    # #     # #    # #    # #      #    # #    # 
#     # #        #####  ######   #   #     # #    # ###### #    # #     #  ####   ####  ######  ####   ####  

;	Straight MPLibrary wrapper: returns value via passed ptr
;	In Universal Interfaces: no

	DeclareMPCall	123, MPGetAreaAccess

MPGetAreaAccess

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass

	bne		ReleaseAndReturnMPCallInvalidIDErr
	mr		r31, r8
	lwz		r16, Area.LogicalBase(r31)
	lwz		r17, Area.LogicalEnd(r31)
	lwz		r18,  0x0020(r31)
	cmplw	r4, r16
	cmplw	cr1, r4, r17
	blt		ReleaseAndReturnParamErrFromMPCall
	bgt		cr1, ReleaseAndReturnParamErrFromMPCall
	rlwinm.	r8, r18,  0, 16, 16
	lwz		r5,  0x001c(r31)

;	r1 = kdp
	bne		ReleaseAndReturnZeroFromMPCall

	_Lock			PSA.HTABLock, scratch1=r14, scratch2=r15

	mr		r8, r4
	bl		SpaceGetPagePLE ; LogicalPage *r8, Area *r31 // PLE *r30, notfound cr0.eq
	beq		SpacePanicIsland
	bl		GetPTEFromPLE ; PLE *r30 // PTE r16/r17, PTE *r18, PTEflags cr0, PLEflags cr5-7
	bcl		BO_IF, Area.kPLEFlagIsInHTAB, InvalPTE ; page *r8, PTE r16/r17, PTE *r18, PLE *r30 // PLEflags cr5-7
	bcl		BO_IF, Area.kPLEFlagIsInHTAB, DeletePTE ; PTE *r18, PLE *r30
	lwz		r17,  0x0000(r30)
	_AssertAndRelease	PSA.HTABLock, scratch=r14
	bl		major_0x10d38
	mr		r5, r18

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall



#     # ######   #####                  #                         ######                                       ######                                              
##   ## #     # #     # ###### #####   # #   #####  ######   ##   #     #   ##    ####  #    # # #    #  ####  #     # #####   ####  #    # # #####  ###### #####  
# # # # #     # #       #        #    #   #  #    # #       #  #  #     #  #  #  #    # #   #  # ##   # #    # #     # #    # #    # #    # # #    # #      #    # 
#  #  # ######   #####  #####    #   #     # #    # #####  #    # ######  #    # #      ####   # # #  # #      ######  #    # #    # #    # # #    # #####  #    # 
#     # #             # #        #   ####### #####  #      ###### #     # ###### #      #  #   # #  # # #  ### #       #####  #    # #    # # #    # #      #####  
#     # #       #     # #        #   #     # #   #  #      #    # #     # #    # #    # #   #  # #   ## #    # #       #   #  #    #  #  #  # #    # #      #   #  
#     # #        #####  ######   #   #     # #    # ###### #    # ######  #    #  ####  #    # # #    #  ####  #       #    #  ####    ##   # #####  ###### #    # 

;	Does the blue task always get these notifications?

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: no

;	ARG		AreaID r3, NotificationID r4, long r5
;	RET		OSErr r3

	DeclareMPCall	77, MPSetAreaBackingProvider

MPSetAreaBackingProvider

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	;	Expect Area ID in r3
	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass
	bne		ReleaseAndReturnMPCallInvalidIDErr
	mr		r31, r8

	;	r4 optionally contains...
	mr.		r8, r4
	beq		@no_notification

	;	a Notification ID
 	bl		LookupID
	cmpwi	r9, Notification.kIDClass
	bne		ReleaseAndReturnMPCallInvalidIDErr
@no_notification

	stw		r4, Area.BackingProviderID(r31)
	stw		r5, Area.BackingProviderMisc(r31)

	b		ReleaseAndReturnZeroFromMPCall



#     # ######   #####                               #######  #####  
##   ## #     # #     #   ##   #      #              #    #  #     # 
# # # # #     # #        #  #  #      #                  #   #     # 
#  #  # ######  #       #    # #      #                 #     #####  
#     # #       #       ###### #      #                #     #     # 
#     # #       #     # #    # #      #                #     #     # 
#     # #        #####  #    # ###### ######  ######   #      #####  

;	Dump Area info to userspace

	DeclareMPCall	78, MPCall_78

MPCall_78	;	OUTSIDE REFERER

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass

	bne		ReleaseAndReturnMPCallInvalidIDErr
	mr		r31, r8
	cmpwi	r4,  0x01
	bne		ReleaseAndReturnParamErrFromMPCall
	cmplwi	r5,  0x00
	bne		MPCall_78_0x68
	li		r16,  0x01
	stw		r16,  0x0134(r6)
	lwz		r16, Area.ProcessID(r31)
	stw		r16,  0x013c(r6)
	lwz		r16, Area.AddressSpaceID(r31)
	stw		r16,  0x0144(r6)
	lwz		r16,  0x0014(r31)
	stw		r16,  0x014c(r6)
	li		r16,  0x10
	stw		r16,  0x0154(r6)

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall

MPCall_78_0x68
	cmplwi	r5,  0x10
	bne		MPCall_78_0x9c
	lwz		r16,  0x0018(r31)
	stw		r16,  0x0134(r6)
	lwz		r16,  0x001c(r31)
	stw		r16,  0x013c(r6)
	lwz		r16,  0x0020(r31)
	stw		r16,  0x0144(r6)
	lwz		r16, Area.LogicalBase(r31)
	stw		r16,  0x014c(r6)
	li		r16,  0x10
	stw		r16,  0x0154(r6)

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall

MPCall_78_0x9c
	cmplwi	r5,  0x20
	bne		MPCall_78_0xd0
	lwz		r16, Area.Length(r31)
	stw		r16,  0x0134(r6)
	lwz		r16, Area.LogicalSeparation(r31)
	stw		r16,  0x013c(r6)
	lwz		r16,  0x0034(r31)
	stw		r16,  0x0144(r6)
	lwz		r16, Area.BytesMapped(r31)
	stw		r16,  0x014c(r6)
	li		r16,  0x10
	stw		r16,  0x0154(r6)

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall

MPCall_78_0xd0
	cmplwi	r5,  0x30
	bne		MPCall_78_0xfc
	lwz		r16,  0x0068(r31)
	stw		r16,  0x0134(r6)
	lwz		r16,  0x0080(r31)
	stw		r16,  0x013c(r6)
	lwz		r16,  0x0084(r31)
	stw		r16,  0x0144(r6)
	li		r16,  0x0c
	stw		r16,  0x0154(r6)

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall

MPCall_78_0xfc
	cmpwi	r5,  0x3c
	bne		ReleaseAndReturnParamErrFromMPCall
	li		r16,  0x00
	stw		r16,  0x0154(r6)

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall



#     # ######   #####               #     #                        #                         ### ######  
##   ## #     # #     # ###### ##### ##    # ###### #    # #####   # #   #####  ######   ##    #  #     # 
# # # # #     # #       #        #   # #   # #       #  #    #    #   #  #    # #       #  #   #  #     # 
#  #  # ######  #  #### #####    #   #  #  # #####    ##     #   #     # #    # #####  #    #  #  #     # 
#     # #       #     # #        #   #   # # #        ##     #   ####### #####  #      ######  #  #     # 
#     # #       #     # #        #   #    ## #       #  #    #   #     # #   #  #      #    #  #  #     # 
#     # #        #####  ######   #   #     # ###### #    #   #   #     # #    # ###### #    # ### ######  

;	OSStatus MPGetNextAreaID(MPAddressSpaceID owningSpaceID, MPAreaID *areaID)

;	Straight MPLibrary wrapper: returns value via passed ptr
;	In Universal Interfaces: yes

	DeclareMPCall	79, MPGetNextAreaID

MPGetNextAreaID

	mr.		r8, r3
	mfsprg	r28, 0
	lwz		r31, EWA.PA_CurAddressSpace(r28)
	beq		MPCall_79_0x20
 	bl		LookupID
	cmpwi	r9, AddressSpace.kIDClass

	bne		ReturnMPCallInvalidIDErr
	mr		r31, r8

MPCall_79_0x20
	lwz		r3, Area.ID(r31)

MPCall_79_0x24
	mr		r8, r4
	li		r9,  0x0b
	bl		GetNextIDOfClass
	cmpwi	r8,  0x00
	beq		ReturnMPCallInvalidIDErr
	mr		r4, r8
	bl		LookupID
;	r8 = something not sure what
;	r9 = 0:inval, 1:proc, 2:task, 3:timer, 4:q, 5:sema, 6:cr, 7:cpu, 8:addrspc, 9:evtg, 10:cgrp, 11:area, 12:not, 13:log

	lwz		r16,  0x0010(r8)
	cmpw	r16, r3
	bne		MPCall_79_0x24
	b		ReturnZeroFromMPCall



#     # ######   #####                  #                         #######                         #                                              
##   ## #     # #     # ###### #####   # #   #####  ######   ##   #       #####   ####  #    #   # #   #####  #####  #####  ######  ####   ####  
# # # # #     # #       #        #    #   #  #    # #       #  #  #       #    # #    # ##  ##  #   #  #    # #    # #    # #      #      #      
#  #  # ######  #  #### #####    #   #     # #    # #####  #    # #####   #    # #    # # ## # #     # #    # #    # #    # #####   ####   ####  
#     # #       #     # #        #   ####### #####  #      ###### #       #####  #    # #    # ####### #    # #    # #####  #           #      # 
#     # #       #     # #        #   #     # #   #  #      #    # #       #   #  #    # #    # #     # #    # #    # #   #  #      #    # #    # 
#     # #        #####  ######   #   #     # #    # ###### #    # #       #    #  ####  #    # #     # #####  #####  #    # ######  ####   ####  

;	Straight MPLibrary wrapper: returns value via passed ptr
;	In Universal Interfaces: yes

	DeclareMPCall	80, MPGetAreaFromAddress

MPGetAreaFromAddress

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr.		r8, r3
	mfsprg	r9, 0
	bne		MPCall_80_0x2c
	lwz		r8, EWA.PA_CurAddressSpace(r9)
	b		MPCall_80_0x38

MPCall_80_0x2c 	bl		LookupID
	cmpwi	r9, AddressSpace.kIDClass

	bne		ReleaseAndReturnMPCallInvalidIDErr

MPCall_80_0x38
	mr		r9, r4
	bl		FindAreaAbove
	lwz		r16,  0x0024(r8)
	li		r5,  0x00
	cmplw	r16, r4
	bgt		ReleaseAndReturnParamErrFromMPCall
	lwz		r5,  0x0000(r8)

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall



#     # ######   #####               #     #                        #                         #######                         #                                              
##   ## #     # #     # ###### ##### ##    # ###### #    # #####   # #   #####  ######   ##   #       #####   ####  #    #   # #   #####  #####  #####  ######  ####   ####  
# # # # #     # #       #        #   # #   # #       #  #    #    #   #  #    # #       #  #  #       #    # #    # ##  ##  #   #  #    # #    # #    # #      #      #      
#  #  # ######  #  #### #####    #   #  #  # #####    ##     #   #     # #    # #####  #    # #####   #    # #    # # ## # #     # #    # #    # #    # #####   ####   ####  
#     # #       #     # #        #   #   # # #        ##     #   ####### #####  #      ###### #       #####  #    # #    # ####### #    # #    # #####  #           #      # 
#     # #       #     # #        #   #    ## #       #  #    #   #     # #   #  #      #    # #       #   #  #    # #    # #     # #    # #    # #   #  #      #    # #    # 
#     # #        #####  ######   #   #     # ###### #    #   #   #     # #    # ###### #    # #       #    #  ####  #    # #     # #####  #####  #    # ######  ####   ####  

;	Straight MPLibrary wrapper: returns value via passed ptr
;	In Universal Interfaces: yes

	DeclareMPCall	125, MPGetNextAreaFromAddress

MPGetNextAreaFromAddress

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr.		r8, r3
	mfsprg	r9, 0
	bne		MPCall_125_0x2c
	lwz		r8, EWA.PA_CurAddressSpace(r9)
	b		MPCall_125_0x38

MPCall_125_0x2c 	bl		LookupID
	cmpwi	r9, AddressSpace.kIDClass

	bne		ReleaseAndReturnMPCallInvalidIDErr

MPCall_125_0x38
	mr		r9, r4
	bl		FindAreaAbove
	lwz		r16,  0x0024(r8)
	li		r5,  0x00
	cmplw	r16, r4
	bgt		MPCall_125_0x58
	lwz		r8,  0x005c(r8)
	addi	r8, r8, -0x54

MPCall_125_0x58
	lwz		r9,  0x002c(r8)
	cmpwi	r9, noErr
	beq		ReleaseAndReturnParamErrFromMPCall
	lwz		r5,  0x0000(r8)

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall



#     # ######   #####               ######                                                #                                              
##   ## #     # #     # ###### ##### #     # #    # #   #  ####  #  ####    ##   #        # #   #####  #####  #####  ######  ####   ####  
# # # # #     # #       #        #   #     # #    #  # #  #      # #    #  #  #  #       #   #  #    # #    # #    # #      #      #      
#  #  # ######  #  #### #####    #   ######  ######   #    ####  # #      #    # #      #     # #    # #    # #    # #####   ####   ####  
#     # #       #     # #        #   #       #    #   #        # # #      ###### #      ####### #    # #    # #####  #           #      # 
#     # #       #     # #        #   #       #    #   #   #    # # #    # #    # #      #     # #    # #    # #   #  #      #    # #    # 
#     # #        #####  ######   #   #       #    #   #    ####  #  ####  #    # ###### #     # #####  #####  #    # ######  ####   ####  

;	Straight MPLibrary wrapper: no
;	In Universal Interfaces: no

	DeclareMPCall	81, MPGetPhysicalAddress

MPGetPhysicalAddress

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass

	mr		r31, r8
	bne		ReleaseAndReturnMPCallInvalidIDErr
	lwz		r16, Area.LogicalBase(r31)
	lwz		r17, Area.LogicalEnd(r31)
	lwz		r18,  0x0020(r31)
	cmplw	r4, r16
	cmplw	cr1, r4, r17
	blt		ReleaseAndReturnParamErrFromMPCall
	bgt		cr1, ReleaseAndReturnParamErrFromMPCall
	rlwinm.	r8, r18,  0, 16, 16
	lwz		r19,  0x0070(r31)
	beq		MPCall_81_0x70
	lwz		r17, Area.BytesMapped(r31)
	rlwinm	r19, r19,  0,  0, 19
	cmpwi	r17,  0x00
	subf	r18, r16, r4
	beq		ReleaseAndReturnParamErrFromMPCall
	add		r5, r18, r19

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall

MPCall_81_0x70
	li		r3,  0x00

	_Lock			PSA.HTABLock, scratch1=r14, scratch2=r15

	mr		r8, r4
	bl		SpaceGetPagePLE ; LogicalPage *r8, Area *r31 // PLE *r30, notfound cr0.eq
	bl		GetPTEFromPLE ; PLE *r30 // PTE r16/r17, PTE *r18, PTEflags cr0, PLEflags cr5-7
	bc		BO_IF_NOT, Area.kPLEFlagHasPhysPage, MPCall_81_0xc8
	mr		r5, r17
	rlwimi	r5, r4,  0, 20, 31

MPCall_81_0xa4
	_AssertAndRelease	PSA.HTABLock, scratch=r8
	b		ReleaseAndReturnMPCall

MPCall_81_0xc8
	li		r3, kMPInsufficientResourcesErr
	b		MPCall_81_0xa4



#     # ######   #####               ######                                             #######                                  
##   ## #     # #     # ###### ##### #     # #    # #   #  ####  #  ####    ##   #      #       #    # ##### ###### #    # ##### 
# # # # #     # #       #        #   #     # #    #  # #  #      # #    #  #  #  #      #        #  #    #   #      ##   #   #   
#  #  # ######  #  #### #####    #   ######  ######   #    ####  # #      #    # #      #####     ##     #   #####  # #  #   #   
#     # #       #     # #        #   #       #    #   #        # # #      ###### #      #         ##     #   #      #  # #   #   
#     # #       #     # #        #   #       #    #   #   #    # # #    # #    # #      #        #  #    #   #      #   ##   #   
#     # #        #####  ######   #   #       #    #   #    ####  #  ####  #    # ###### ####### #    #   #   ###### #    #   #   

;	Straight MPLibrary wrapper: no
;	In Universal Interfaces: no

	DeclareMPCall	98, MPGetPhysicalExtent

MPGetPhysicalExtent

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass

	mr		r31, r8
	bne		ReleaseAndReturnMPCallInvalidIDErr
	lwz		r16, Area.LogicalBase(r31)
	lwz		r17, Area.LogicalEnd(r31)
	mr		r29, r5
	add		r5, r5, r4
	lwz		r18,  0x0020(r31)
	addi	r5, r5, -0x01
	cmplw	r4, r16
	cmplw	cr1, r5, r17
	blt		ReleaseAndReturnParamErrFromMPCall
	bgt		cr1, ReleaseAndReturnParamErrFromMPCall
	lwz		r20, Area.BytesMapped(r31)
	rlwinm.	r8, r18,  0, 16, 16
	cmpwi	cr1, r20,  0x00
	beq		MPCall_98_0x84
	beq		cr1, ReleaseAndReturnParamErrFromMPCall
	lwz		r19,  0x0070(r31)
	subf	r18, r16, r4
	rlwinm	r19, r19,  0,  0, 19
	add		r16, r18, r19
	stw		r16,  0x0134(r6)
	stw		r29,  0x013c(r6)

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall

MPCall_98_0x84

	_Lock			PSA.HTABLock, scratch1=r14, scratch2=r15

	mr		r8, r4
	mr		r28, r4
	bl		SpaceGetPagePLE ; LogicalPage *r8, Area *r31 // PLE *r30, notfound cr0.eq
	beq		SpacePanicIsland
	bl		GetPTEFromPLE ; PLE *r30 // PTE r16/r17, PTE *r18, PTEflags cr0, PLEflags cr5-7
	crclr	cr3_eq
	li		r3,  0x00
	bso		cr7, MPCall_98_0xc4
	crset	cr3_eq
	li		r3, kMPInsufficientResourcesErr

MPCall_98_0xc4
	rlwimi	r17, r4,  0, 20, 31
	rlwinm	r29, r17,  0,  0, 19
	stw		r17,  0x0134(r6)

MPCall_98_0xd0
	lwz		r16,  0x0068(r31)
	add		r28, r28, r16
	add		r29, r29, r16
	cmplw	cr2, r28, r5
	bgt		cr2, MPCall_98_0x140
	mr		r8, r28
	bl		SpaceGetPagePLE ; LogicalPage *r8, Area *r31 // PLE *r30, notfound cr0.eq
	beq		SpacePanicIsland
	bl		GetPTEFromPLE ; PLE *r30 // PTE r16/r17, PTE *r18, PTEflags cr0, PLEflags cr5-7
	rlwinm	r17, r17,  0,  0, 19
	crxor	31, 31, 14
	bc		BO_IF_NOT, Area.kPLEFlagHasPhysPage, MPCall_98_0x10c
	beq		cr3, MPCall_98_0xd0
	cmplw	r29, r17
	beq		MPCall_98_0xd0

MPCall_98_0x10c
	lwz		r16,  0x007c(r31)
	and		r28, r28, r16
	subf	r16, r4, r28

MPCall_98_0x118
	stw		r16,  0x013c(r6)
	_AssertAndRelease	PSA.HTABLock, scratch=r8
	b		ReleaseAndReturnMPCall

MPCall_98_0x140
	addi	r5, r5,  0x01
	beq		cr3, MPCall_98_0x170
	mr		r8, r28
	bl		SpaceGetPagePLE ; LogicalPage *r8, Area *r31 // PLE *r30, notfound cr0.eq
	beq		SpacePanicIsland
	bl		GetPTEFromPLE ; PLE *r30 // PTE r16/r17, PTE *r18, PTEflags cr0, PLEflags cr5-7
	rlwinm	r17, r17,  0,  0, 19
	bc		BO_IF_NOT, Area.kPLEFlagHasPhysPage, MPCall_98_0x170
	cmplw	r29, r17
	bne		MPCall_98_0x170
	subf	r16, r4, r5
	b		MPCall_98_0x118

MPCall_98_0x170
	lwz		r16,  0x007c(r31)
	and		r28, r28, r16
	cmplw	r5, r28
	bge		MPCall_98_0x184
	mr		r28, r5

MPCall_98_0x184
	subf	r16, r4, r28
	b		MPCall_98_0x118



#     # ######  ######                                                #                         
##   ## #     # #     # ######  ####  #  ####  ##### ###### #####    # #    ####  ###### #####  
# # # # #     # #     # #      #    # # #        #   #      #    #  #   #  #    # #      #    # 
#  #  # ######  ######  #####  #      #  ####    #   #####  #    # #     # #      #####  #    # 
#     # #       #   #   #      #  ### #      #   #   #      #####  ####### #  ### #      #####  
#     # #       #    #  #      #    # # #    #   #   #      #   #  #     # #    # #      #   #  
#     # #       #     # ######  ####  #  ####    #   ###### #    # #     #  ####  ###### #    # 

;	ARG		MPNotificationID r3
;	RET		OSStatus r3

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: no

	DeclareMPCall	82, MPRegisterAger

MPRegisterAger

	;	May only register the ager once
	lwz		r8, PSA.AgerID(r1)
	cmpwi	r8, 0
	bne		ReturnMPCallOOM

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Notification.kIDClass
	bne		ReleaseAndReturnMPCallInvalidIDErr

	stw		r3, PSA.AgerID(r1)

	b		ReleaseAndReturnZeroFromMPCall



#     # ######   #####               #######                      ######                       
##   ## #     # #     # ###### ##### #       #####  ###### ###### #     #   ##    ####  ###### 
# # # # #     # #       #        #   #       #    # #      #      #     #  #  #  #    # #      
#  #  # ######  #  #### #####    #   #####   #    # #####  #####  ######  #    # #      #####  
#     # #       #     # #        #   #       #####  #      #      #       ###### #  ### #      
#     # #       #     # #        #   #       #   #  #      #      #       #    # #    # #      
#     # #        #####  ######   #   #       #    # ###### ###### #       #    #  ####  ###### 

;	Pop page from system free list

;	RET		OSStatus r3, PhysicalPage *r4

;	Straight MPLibrary wrapper: returns value via passed ptr
;	In Universal Interfaces: no

	DeclareMPCall	83, MPGetFreePage

MPGetFreePage

	_Lock				PSA.PoolLock, scratch1=r16, scratch2=r17
	bl		FreePageListPop ; // PhysicalPage *r8
	_AssertAndRelease	PSA.PoolLock, scratch=r16

	;	Success
	mr.		r4, r8
	bne		ReturnZeroFromMPCall

	;	Failure. Fall through to something horrible!

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17



#     #                         #                                       #     #                   #                         
##   ## #    #  ####  #    #   # #   #####   ####  #    # #    # #####  #  #  # # ##### #    #   # #    ####  ###### #####  
# # # # #    # #    # #   #   #   #  #    # #    # #    # ##   # #    # #  #  # #   #   #    #  #   #  #    # #      #    # 
#  #  # #    # #      ####   #     # #    # #    # #    # # #  # #    # #  #  # #   #   ###### #     # #      #####  #    # 
#     # #    # #      #  #   ####### #####  #    # #    # #  # # #    # #  #  # #   #   #    # ####### #  ### #      #####  
#     # #    # #    # #   #  #     # #   #  #    # #    # #   ## #    # #  #  # #   #   #    # #     # #    # #      #   #  
#     #  ####   ####  #    # #     # #    #  ####   ####  #    # #####   ## ##  #   #   #    # #     #  ####  ###### #    # 

FailMPCallAndNotifyAgerWeNeedPages

	lwz		r8, PSA.AgerID(r1)
 	bl		LookupID
	cmpwi	r9, Notification.kIDClass
	mr		r31, r8
	bne		ReleaseAndReturnMPCallOOM

	lwz		r8, Notification.EventGroupID(r31)
 	bl		LookupID
	cmpwi	r9, EventGroup.kIDClass
	mr		r31, r8
	bne		ReleaseAndReturnMPCallOOM

	;	Huh? Event Groups are 32 bytes. Bug?
	lwz		r8, 0x20(r31)
	bl		SetEvent

	b		ReleaseAndReturnMPCallOOM



#######                      ######                       #                      ######                
#       #####  ###### ###### #     #   ##    ####  ###### #       #  ####  ##### #     #  ####  #####  
#       #    # #      #      #     #  #  #  #    # #      #       # #        #   #     # #    # #    # 
#####   #    # #####  #####  ######  #    # #      #####  #       #  ####    #   ######  #    # #    # 
#       #####  #      #      #       ###### #  ### #      #       #      #   #   #       #    # #####  
#       #   #  #      #      #       #    # #    # #      #       # #    #   #   #       #    # #      
#       #    # ###### ###### #       #    #  ####  ###### ####### #  ####    #   #        ####  #      

;	Requires PoolLock to be acquired!

FreePageListPop ; // PhysicalPage *r8

	addi	r18, r1, PSA.FreeList
	lwz		r8, PSA.FreeList + LLL.Next(r1)
	cmpw	r8, r18
	beq		@fail

	RemoveFromList		r8, scratch1=r16, scratch2=r17

	lwz		r16, PSA.FreePageCount(r1)
	subi	r16, r16, 1
	stw		r16, PSA.FreePageCount(r1)

	;	Daniel found the bug here!
	lwz		r17, LLL.Signature(r8)
	mfspr	r16, dec
	eqv.	r17, r18, r17

	stw		r16, 0(r8)
	bne		SpacePanicIsland
	stw		r16, 4(r8)
	stw		r16, 8(r8)
	stw		r16, 12(r8)

	blr

@fail
	li		r8, 0
	blr



#     # ######  ######               #######                      ######                       
##   ## #     # #     # #    # ##### #       #####  ###### ###### #     #   ##    ####  ###### 
# # # # #     # #     # #    #   #   #       #    # #      #      #     #  #  #  #    # #      
#  #  # ######  ######  #    #   #   #####   #    # #####  #####  ######  #    # #      #####  
#     # #       #       #    #   #   #       #####  #      #      #       ###### #  ### #      
#     # #       #       #    #   #   #       #   #  #      #      #       #    # #    # #      
#     # #       #        ####    #   #       #    # ###### ###### #       #    #  ####  ###### 

;	Checks some junk in the page first (consider removing this)

;	ARG		PhysicalPage *r3
;	RET		OSStatus r3

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: no

	DeclareMPCall	84, MPPutFreePage

MPPutFreePage

	_Lock			PSA.PoolLock, scratch1=r16, scratch2=r17

	lwz		r16, 4(r3)
	lwz		r17, 0(r3)

	addi	r18, r1, PSA.FreeList
	eqv.	r16, r16, r17
	cmpw	cr1, r17, r18
	bne		@succeed
	bne		cr1, @succeed

	li		r3, paramErr
	b		@return

@succeed
	mr		r8, r3
	bl		FreePageListPush ; PhysicalPage *r8
	li		r3, 0

@return
	_AssertAndRelease	PSA.PoolLock, scratch=r16

	b		CommonMPCallReturnPath



#######                      ######                       #                      ######                       
#       #####  ###### ###### #     #   ##    ####  ###### #       #  ####  ##### #     # #    #  ####  #    # 
#       #    # #      #      #     #  #  #  #    # #      #       # #        #   #     # #    # #      #    # 
#####   #    # #####  #####  ######  #    # #      #####  #       #  ####    #   ######  #    #  ####  ###### 
#       #####  #      #      #       ###### #  ### #      #       #      #   #   #       #    #      # #    # 
#       #   #  #      #      #       #    # #    # #      #       # #    #   #   #       #    # #    # #    # 
#       #    # ###### ###### #       #    #  ####  ###### ####### #  ####    #   #        ####   ####  #    # 

FreePageListPush ; PhysicalPage *r8

	;	Must be an actual page-aligned address
	clrlwi.	r9, r8, 20
	addi	r9, r1, PSA.FreeList
	bne		SpacePanicIsland


	;	This is probably an alternative to heavyweight locks around the free list

	stw		r9, 0(r8)		;	store &parent in Freeform field

	InsertAsPrev	r8, r9, scratch=r16

	not		r9, r9
	stw		r9, 4(r8)		;	store ^&parent in Signature field


	lwz		r8, PSA.FreePageCount(r1)
	addi	r8, r8, 1
	stw		r8, PSA.FreePageCount(r1)

	blr



#     # ######   #####               #######                      ######                        #####                             
##   ## #     # #     # ###### ##### #       #####  ###### ###### #     #   ##    ####  ###### #     #  ####  #    # #    # ##### 
# # # # #     # #       #        #   #       #    # #      #      #     #  #  #  #    # #      #       #    # #    # ##   #   #   
#  #  # ######  #  #### #####    #   #####   #    # #####  #####  ######  #    # #      #####  #       #    # #    # # #  #   #   
#     # #       #     # #        #   #       #####  #      #      #       ###### #  ### #      #       #    # #    # #  # #   #   
#     # #       #     # #        #   #       #   #  #      #      #       #    # #    # #      #     # #    # #    # #   ##   #   
#     # #        #####  ######   #   #       #    # ###### ###### #       #    #  ####  ######  #####   ####   ####  #    #   #   

;	RET		r3

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: no

	DeclareMPCall	100, MPGetFreePageCount

MPGetFreePageCount

	lwz		r3, PSA.FreePageCount(r1)
	b		CommonMPCallReturnPath



#     # ######   #####               #     #                                    ######                        #####                             
##   ## #     # #     # ###### ##### #     # #    # #    # ###### #      #####  #     #   ##    ####  ###### #     #  ####  #    # #    # ##### 
# # # # #     # #       #        #   #     # ##   # #    # #      #      #    # #     #  #  #  #    # #      #       #    # #    # ##   #   #   
#  #  # ######  #  #### #####    #   #     # # #  # ###### #####  #      #    # ######  #    # #      #####  #       #    # #    # # #  #   #   
#     # #       #     # #        #   #     # #  # # #    # #      #      #    # #       ###### #  ### #      #       #    # #    # #  # #   #   
#     # #       #     # #        #   #     # #   ## #    # #      #      #    # #       #    # #    # #      #     # #    # #    # #   ##   #   
#     # #        #####  ######   #    #####  #    # #    # ###### ###### #####  #       #    #  ####  ######  #####   ####   ####  #    #   #   

;	RET		r3

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: no

	DeclareMPCall	101, MPGetUnheldPageCount

MPGetUnheldPageCount

	lwz		r3, PSA.UnheldFreePageCount(r1)
	b		CommonMPCallReturnPath



#     # ######  #     #               ######                       
##   ## #     # ##   ##   ##   #####  #     #   ##    ####  ###### 
# # # # #     # # # # #  #  #  #    # #     #  #  #  #    # #      
#  #  # ######  #  #  # #    # #    # ######  #    # #      #####  
#     # #       #     # ###### #####  #       ###### #  ### #      
#     # #       #     # #    # #      #       #    # #    # #      
#     # #       #     # #    # #      #       #    #  ####  ###### 

;	ARG		MPAreaID r3

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: no

	DeclareMPCall	85, MPMapPage

MPMapPage

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass
	bne		ReleaseAndReturnMPCallInvalidIDErr
	mr		r31, r8

	lwz		r16, Area.Flags(r31)
	rlwinm.	r8, r16, 0, Area.kAliasFlag, Area.kAliasFlag
	bne		ReleaseAndReturnParamErrFromMPCall

	lwz		r16, Area.LogicalBase(r31)
	lwz		r17, Area.LogicalEnd(r31)
	lwz		r19, Area.FlagsAndMinAlign(r31)
	cmplw	r4, r16
	cmplw	cr1, r4, r17
	blt		ReleaseAndReturnParamErrFromMPCall
	bgt		cr1, ReleaseAndReturnParamErrFromMPCall

	rlwinm.	r8, r19, 0, 16, 16				; test Contig bit of FlagsAndMinAlign
	cmplw	cr1, r4, r16
	lwz		r20, Area.BytesMapped(r31)
	beq		@not_contig_area
	bne		cr1, ReleaseAndReturnParamErrFromMPCall

;is contig area

	cmpwi	r20, 0
	lwz		r8, Area.ContigPTETemplate(r31)
	bne		ReleaseAndReturnMPCallOOM
	rlwimi	r8, r5, 0, 0xFFFFF000
	lwz		r18, Area.DefaultAlignmentMask(r31)
	lwz		r20, Area.Length(r31)
	stw		r8, Area.ContigPTETemplate(r31)
	stw		r20, Area.BytesMapped(r31)

	b		ReleaseAndReturnZeroFromMPCall

@not_contig_area

	_Lock			PSA.HTABLock, scratch1=r14, scratch2=r15

	mr		r8, r4
	bl		SpaceGetPagePLE ; LogicalPage *r8, Area *r31 // PLE *r30, notfound cr0.eq
	beq		SpacePanicIsland

	lwz		r29, 0(r30)
	_AssertAndRelease	PSA.HTABLock, scratch=r14

	rlwinm.	r8, r29, 0, 31, 31
	bne		ReleaseAndReturnMPCallOOM

	lwz		r17, ContextBlock.r6(r6)
	rlwinm.	r8, r17, 0, 30, 30
	bne		KCMapPage_0x12c

	_Lock				PSA.PoolLock, scratch1=r16, scratch2=r17
	bl		FreePageListPop ; // PhysicalPage *r8
	_AssertAndRelease	PSA.PoolLock, scratch=r16

	mr.		r5, r8
	beq		FailMPCallAndNotifyAgerWeNeedPages

KCMapPage_0x12c
	lwz		r17,  0x0134(r6)
	rlwinm.	r8, r17,  0, 29, 29
	beq		KCMapPage_0x17c
	rlwinm.	r8, r29,  0, 25, 25
	lwz		r18,  0x0068(r31)

KCMapPage_0x140
	addi	r18, r18, -0x20
	bne		KCMapPage_0x174
	dcbst	r18, r5

KCMapPage_0x14c
	cmpwi	cr1, r18,  0x00
	bgt		cr1, KCMapPage_0x140
	sync
	lwz		r18,  0x0068(r31)

KCMapPage_0x15c
	addi	r18, r18, -0x20
	icbi	r18, r5
	cmpwi	cr1, r18,  0x00
	bgt		cr1, KCMapPage_0x15c
	isync
	b		KCMapPage_0x17c

KCMapPage_0x174
	dcbf	r18, r5
	b		KCMapPage_0x14c

KCMapPage_0x17c
	lwz		r18,  0x0068(r31)
	andi.	r29, r29,  0x7e7
	ori		r29, r29,  0x01
	rlwimi	r29, r5,  0,  0, 19
	lwz		r17, Area.BytesMapped(r31)
	stw		r29,  0x0000(r30)
	add		r17, r17, r18
	stw		r17, Area.BytesMapped(r31)
	lwz		r17,  0x0134(r6)
	clrlwi.	r8, r17,  0x1f

;	r1 = kdp
	beq		ReleaseAndReturnZeroFromMPCall
	lwz		r5,  0x0068(r31)
	b		HoldPages



#     # ######  #     #                             ######                              
##   ## #     # #     # #    # #    #   ##   #####  #     #   ##    ####  ######  ####  
# # # # #     # #     # ##   # ##  ##  #  #  #    # #     #  #  #  #    # #      #      
#  #  # ######  #     # # #  # # ## # #    # #    # ######  #    # #      #####   ####  
#     # #       #     # #  # # #    # ###### #####  #       ###### #  ### #           # 
#     # #       #     # #   ## #    # #    # #      #       #    # #    # #      #    # 
#     # #        #####  #    # #    # #    # #      #       #    #  ####  ######  ####  

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: no

	DeclareMPCall	86, MPUnmapPages

MPUnmapPages

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass

	bne		ReleaseAndReturnMPCallInvalidIDErr
	mr		r31, r8
	lwz		r8,  0x0134(r6)
	lwz		r16, Area.Flags(r31)
	rlwinm.	r16, r16,  0, 28, 28
	bne		ReleaseAndReturnParamErrFromMPCall
	clrlwi.	r8, r8,  0x1f
	add		r5, r5, r4
	lwz		r16, Area.LogicalBase(r31)
	lwz		r17, Area.LogicalEnd(r31)
	lwz		r19,  0x0020(r31)
	crmove	14, 2
	addi	r5, r5, -0x01
	cmplw	r4, r16
	cmplw	cr1, r5, r17
	blt		ReleaseAndReturnParamErrFromMPCall
	bgt		cr1, ReleaseAndReturnParamErrFromMPCall
	lwz		r29,  0x0068(r31)
	lwz		r20, Area.BytesMapped(r31)
	rlwinm.	r8, r19,  0, 16, 16
	cmplw	cr1, r4, r16
	beq		KCUnmapPages_0xd8
	bne		cr1, ReleaseAndReturnParamErrFromMPCall
	cmpwi	r20,  0x00
	li		r20,  0x00
	ble		ReleaseAndReturnMPCallOOM
	stw		r20, Area.BytesMapped(r31)

	_Lock			PSA.HTABLock, scratch1=r14, scratch2=r15

	li		r30,  0x00

KCUnmapPages_0xac
	mr		r8, r4
	lwz		r9, Area.AddressSpacePtr(r31)
	bl		SpaceL2PIgnoringBATs ; LogicalPage *r8, MPAddressSpace *r9 // PhysicalPage *r17
	beq		KCUnmapPages_0xc4
	bl		InvalPTE ; page *r8, PTE r16/r17, PTE *r18, PLE *r30 // PLEflags cr5-7
	bl		DeletePTE ; PTE *r18, PLE *r30

KCUnmapPages_0xc4
	add		r4, r4, r29
	subf.	r8, r4, r5
	bge		KCUnmapPages_0xac
	crclr	cr3_eq
	b		KCUnmapPages_0x158

KCUnmapPages_0xd8
	bne		cr3, KCUnmapPages_0xf4

	_Lock			PSA.PoolLock, scratch1=r14, scratch2=r15


KCUnmapPages_0xf4

	_Lock			PSA.HTABLock, scratch1=r14, scratch2=r15

	lwz		r28, Area.BytesMapped(r31)

KCUnmapPages_0x110
	mr		r8, r4
	bl		SpaceGetPagePLE ; LogicalPage *r8, Area *r31 // PLE *r30, notfound cr0.eq
	beq		SpacePanicIsland
	bl		GetPTEFromPLE ; PLE *r30 // PTE r16/r17, PTE *r18, PTEflags cr0, PLEflags cr5-7
	bc		BO_IF_NOT, Area.kPLEFlagHasPhysPage, KCUnmapPages_0x148
	bcl		BO_IF, Area.kPLEFlagIsInHTAB, InvalPTE ; page *r8, PTE r16/r17, PTE *r18, PLE *r30 // PLEflags cr5-7
	bcl		BO_IF, Area.kPLEFlagIsInHTAB, DeletePTE ; PTE *r18, PLE *r30
	lwz		r18,  0x0000(r30)
	subf	r28, r29, r28
	rlwinm	r18, r18,  0,  0, 30
	stw		r18,  0x0000(r30)
	bne		cr3, KCUnmapPages_0x148
	rlwinm	r8, r18,  0,  0, 19

;	r1 = kdp
;	r8 = maybe the page
	bl		FreePageListPush ; PhysicalPage *r8

KCUnmapPages_0x148
	add		r4, r4, r29
	subf.	r8, r4, r5
	bge		KCUnmapPages_0x110
	stw		r28, Area.BytesMapped(r31)

KCUnmapPages_0x158
	_AssertAndRelease	PSA.HTABLock, scratch=r14

;	r1 = kdp
	bne		cr3, ReleaseAndReturnZeroFromMPCall
	_AssertAndRelease	PSA.PoolLock, scratch=r14

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall



#     # ######  #     #                      ######                                                           #####                                                           
##   ## #     # ##   ##   ##   #    # ###### #     # #    # #   #  ####  #  ####    ##   #      #      #   # #     #  ####  #    # ##### #  ####  #    #  ####  #    #  ####  
# # # # #     # # # # #  #  #  #   #  #      #     # #    #  # #  #      # #    #  #  #  #      #       # #  #       #    # ##   #   #   # #    # #    # #    # #    # #      
#  #  # ######  #  #  # #    # ####   #####  ######  ######   #    ####  # #      #    # #      #        #   #       #    # # #  #   #   # #      #    # #    # #    #  ####  
#     # #       #     # ###### #  #   #      #       #    #   #        # # #      ###### #      #        #   #       #    # #  # #   #   # #  ### #    # #    # #    #      # 
#     # #       #     # #    # #   #  #      #       #    #   #   #    # # #    # #    # #      #        #   #     # #    # #   ##   #   # #    # #    # #    # #    # #    # 
#     # #       #     # #    # #    # ###### #       #    #   #    ####  #  ####  #    # ###### ######   #    #####   ####  #    #   #   #  ####   ####   ####   ####   ####  

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: no

	DeclareMPCall	127, MPMakePhysicallyContiguous

MPMakePhysicallyContiguous

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass

	bne		ReleaseAndReturnMPCallInvalidIDErr
	mr		r31, r8
	mr		r27, r5
	add		r5, r5, r4
	lwz		r16, Area.LogicalBase(r31)
	lwz		r17, Area.LogicalEnd(r31)
	addi	r5, r5, -0x01
	cmplw	r4, r16
	cmplw	cr1, r5, r17
	blt		ReleaseAndReturnParamErrFromMPCall
	bgt		cr1, ReleaseAndReturnParamErrFromMPCall
	lwz		r19,  0x0020(r31)
	lwz		r29,  0x0068(r31)
	rlwinm.	r8, r19,  0, 16, 16
	bne		ReleaseAndReturnParamErrFromMPCall

	_Lock			PSA.HTABLock, scratch1=r14, scratch2=r15

	mr		r27, r4
	li		r28, -0x01

NKMakePhysicallyContiguous_0x80
	mr		r8, r27
	bl		SpaceGetPagePLE ; LogicalPage *r8, Area *r31 // PLE *r30, notfound cr0.eq
	beq		SpacePanicIsland
	bl		GetPTEFromPLE ; PLE *r30 // PTE r16/r17, PTE *r18, PTEflags cr0, PLEflags cr5-7
	bc		BO_IF_NOT, Area.kPLEFlagHasPhysPage, NKMakePhysicallyContiguous_0x150
	rlwinm	r8, r17,  0,  0, 19
	cmpwi	r28, -0x01
	cmpw	cr1, r28, r8
	mr		r28, r8
	beq		NKMakePhysicallyContiguous_0xac
	bne		cr1, NKMakePhysicallyContiguous_0xe0

NKMakePhysicallyContiguous_0xac
	add		r27, r27, r29
	add		r28, r28, r29
	subf.	r8, r27, r5
	bge		NKMakePhysicallyContiguous_0x80
	_AssertAndRelease	PSA.HTABLock, scratch=r14

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall

NKMakePhysicallyContiguous_0xe0
	_AssertAndRelease	PSA.HTABLock, scratch=r14

	_Lock			PSA.PoolLock, scratch1=r16, scratch2=r17

	addi	r18, r1, PSA.FreeList
	lwz		r8, PSA.FreeList + LLL.Next(r1)
	cmpw	r8, r18
	beq		NKMakePhysicallyContiguous_0x174
	b		NKMakePhysicallyContiguous_0x174

	;	Dead code:
	_AssertAndRelease	PSA.PoolLock, scratch=r16
	b		ReleaseAndReturnZeroFromMPCall

NKMakePhysicallyContiguous_0x150
	_AssertAndRelease	PSA.HTABLock, scratch=r16
	b		ReleaseAndReturnMPCallOOM

NKMakePhysicallyContiguous_0x174
	_AssertAndRelease	PSA.PoolLock, scratch=r16
	b		ReleaseAndReturnMPCallOOM



#     # ######  #                            ######                              
##   ## #     # #        ####   ####  #    # #     #   ##    ####  ######  ####  
# # # # #     # #       #    # #    # #   #  #     #  #  #  #    # #      #      
#  #  # ######  #       #    # #      ####   ######  #    # #      #####   ####  
#     # #       #       #    # #      #  #   #       ###### #  ### #           # 
#     # #       #       #    # #    # #   #  #       #    # #    # #      #    # 
#     # #       #######  ####   ####  #    # #       #    #  ####  ######  ####  

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: no

	DeclareMPCall	87, MPLockPages

MPLockPages

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass

	bne		ReleaseAndReturnMPCallInvalidIDErr
	mr		r31, r8
	mr		r27, r5
	add		r5, r5, r4
	lwz		r16, Area.LogicalBase(r31)
	lwz		r17, Area.LogicalEnd(r31)
	addi	r5, r5, -0x01
	cmplw	r4, r16
	cmplw	cr1, r5, r17
	blt		ReleaseAndReturnParamErrFromMPCall
	bgt		cr1, ReleaseAndReturnParamErrFromMPCall
	lwz		r19,  0x0020(r31)
	lwz		r29,  0x0068(r31)
	rlwinm.	r8, r19,  0, 16, 16
	bne		ReleaseAndReturnParamErrFromMPCall
	mr		r27, r4
	li		r28,  0x00

KCLockPages_0x68
	mr		r8, r27
	bl		MPCall_95_0x254
	beq		ReleaseAndReturnParamErrFromMPCall
	lhz		r18,  0x0000(r30)
	rlwinm	r17, r18, 24, 25, 31
	rlwinm.	r8, r18,  0, 16, 16
	cmpwi	cr1, r17,  0x7f
	addi	r28, r28,  0x01
	beq		KCLockPages_0x94
	addi	r28, r28, -0x01
	bge		cr1, major_0x0b0cc

KCLockPages_0x94
	add		r27, r27, r29
	subf.	r8, r27, r5
	bge		KCLockPages_0x68

	_Lock			PSA.PoolLock, scratch1=r16, scratch2=r17

	lwz		r16, PSA.UnheldFreePageCount(r1)
	subf.	r16, r28, r16
	ble		KCLockPages_0xc8
	stw		r16, PSA.UnheldFreePageCount(r1)

KCLockPages_0xc8
	_AssertAndRelease	PSA.PoolLock, scratch=r16
	ble		ReleaseAndReturnMPCallOOM
	mr		r27, r4

KCLockPages_0xf0
	mr		r8, r27
	bl		MPCall_95_0x254
	beq		SpacePanicIsland
	lhz		r18,  0x0000(r30)
	rlwinm.	r17, r18,  0, 16, 16
	bne		KCLockPages_0x10c
	li		r18, -0x8000

KCLockPages_0x10c
	rlwinm	r17, r18, 24, 25, 31
	addi	r17, r17,  0x01
	rlwimi	r18, r17,  8, 17, 23
	sth		r18,  0x0000(r30)
	add		r27, r27, r29
	subf.	r8, r27, r5
	bge		KCLockPages_0xf0

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall



#     # ######  #     #                                    ######                              
##   ## #     # #     # #    # #       ####   ####  #    # #     #   ##    ####  ######  ####  
# # # # #     # #     # ##   # #      #    # #    # #   #  #     #  #  #  #    # #      #      
#  #  # ######  #     # # #  # #      #    # #      ####   ######  #    # #      #####   ####  
#     # #       #     # #  # # #      #    # #      #  #   #       ###### #  ### #           # 
#     # #       #     # #   ## #      #    # #    # #   #  #       #    # #    # #      #    # 
#     # #        #####  #    # ######  ####   ####  #    # #       #    #  ####  ######  ####  

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: no

	DeclareMPCall	88, MPUnlockPages

MPUnlockPages

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass

	bne		ReleaseAndReturnMPCallInvalidIDErr
	mr		r31, r8
	add		r5, r5, r4
	lwz		r16, Area.LogicalBase(r31)
	lwz		r17, Area.LogicalEnd(r31)
	addi	r5, r5, -0x01
	cmplw	r4, r16
	cmplw	cr1, r5, r17
	blt		ReleaseAndReturnParamErrFromMPCall
	bgt		cr1, ReleaseAndReturnParamErrFromMPCall
	lwz		r19,  0x0020(r31)
	lwz		r29,  0x0068(r31)
	rlwinm.	r8, r19,  0, 16, 16
	bne		ReleaseAndReturnParamErrFromMPCall
	mr		r27, r4

KCUnlockPages_0x60
	mr		r8, r27
	bl		MPCall_95_0x254
	beq		ReleaseAndReturnParamErrFromMPCall
	lhz		r18,  0x0000(r30)
	rlwinm	r17, r18, 24, 25, 31
	rlwinm.	r8, r18,  0, 16, 16
	cmpwi	cr1, r17,  0x00
	beq		major_0x0b0cc
	addi	r28, r28,  0x01
	beq		cr1, major_0x0b0cc
	add		r27, r27, r29
	subf.	r8, r27, r5
	bge		KCUnlockPages_0x60
	li		r28,  0x00

KCUnlockPages_0x98
	mr		r8, r4
	bl		MPCall_95_0x254
	beq		ReleaseAndReturnParamErrFromMPCall
	lhz		r18,  0x0000(r30)
	rlwinm	r17, r18, 24, 25, 31
	addi	r17, r17, -0x01
	rlwimi	r18, r17,  8, 17, 23
	clrlwi.	r8, r18,  0x11
	bne		KCUnlockPages_0xc4
	rlwinm	r18, r18,  0, 17, 15
	addi	r28, r28,  0x01

KCUnlockPages_0xc4
	sth		r18,  0x0000(r30)
	add		r4, r4, r29
	subf.	r8, r4, r5
	bge		KCUnlockPages_0x98

	_Lock			PSA.PoolLock, scratch1=r16, scratch2=r17

	lwz		r16, PSA.UnheldFreePageCount(r1)
	add		r16, r16, r28
	stw		r16, PSA.UnheldFreePageCount(r1)
	_AssertAndRelease	PSA.PoolLock, scratch=r16

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall



#     # ######  #     #                      ######                              
##   ## #     # #     #  ####  #      #####  #     #   ##    ####  ######  ####  
# # # # #     # #     # #    # #      #    # #     #  #  #  #    # #      #      
#  #  # ######  ####### #    # #      #    # ######  #    # #      #####   ####  
#     # #       #     # #    # #      #    # #       ###### #  ### #           # 
#     # #       #     # #    # #      #    # #       #    # #    # #      #    # 
#     # #       #     #  ####  ###### #####  #       #    #  ####  ######  ####  
                                                                                 
;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: no

	DeclareMPCall	89, MPHoldPages

MPHoldPages

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass
	bne		ReleaseAndReturnMPCallInvalidIDErr
	mr		r31, r8



#     #                      ######                              
#     #  ####  #      #####  #     #   ##    ####  ######  ####  
#     # #    # #      #    # #     #  #  #  #    # #      #      
####### #    # #      #    # ######  #    # #      #####   ####  
#     # #    # #      #    # #       ###### #  ### #           # 
#     # #    # #      #    # #       #    # #    # #      #    # 
#     #  ####  ###### #####  #       #    #  ####  ######  ####  

HoldPages

	add		r5, r5, r4
	lwz		r16, Area.LogicalBase(r31)
	lwz		r17, Area.LogicalEnd(r31)
	addi	r5, r5, -0x01
	cmplw	r4, r16
	cmplw	cr1, r5, r17
	blt		ReleaseAndReturnParamErrFromMPCall
	bgt		cr1, ReleaseAndReturnParamErrFromMPCall
	lwz		r19,  0x0020(r31)
	lwz		r29,  0x0068(r31)
	rlwinm.	r8, r19,  0, 16, 16
	bne		ReleaseAndReturnParamErrFromMPCall
	mr		r27, r4
	li		r28,  0x00

KCHoldPages_0x64
	mr		r8, r27
	bl		MPCall_95_0x254
	beq		ReleaseAndReturnParamErrFromMPCall
	lhz		r18,  0x0000(r30)
	clrlwi	r17, r18,  0x18
	rlwinm.	r8, r18,  0, 16, 16
	cmpwi	cr1, r17,  0xff
	addi	r28, r28,  0x01
	beq		KCHoldPages_0x90
	addi	r28, r28, -0x01
	bge		cr1, major_0x0b0cc

KCHoldPages_0x90
	add		r27, r27, r29
	subf.	r8, r27, r5
	bge		KCHoldPages_0x64

	_Lock			PSA.PoolLock, scratch1=r16, scratch2=r17

	lwz		r16, PSA.UnheldFreePageCount(r1)
	subf.	r16, r28, r16
	ble		KCHoldPages_0xc4
	stw		r16, PSA.UnheldFreePageCount(r1)

KCHoldPages_0xc4
	_AssertAndRelease	PSA.PoolLock, scratch=r16
	ble		ReleaseAndReturnMPCallOOM
	mr		r27, r4

KCHoldPages_0xec
	mr		r8, r27
	bl		MPCall_95_0x254
	beq		SpacePanicIsland
	lhz		r18,  0x0000(r30)
	rlwinm.	r17, r18,  0, 16, 16
	bne		KCHoldPages_0x108
	li		r18, -0x8000

KCHoldPages_0x108
	clrlwi	r17, r18,  0x18
	addi	r17, r17,  0x01
	rlwimi	r18, r17,  0, 24, 31
	sth		r18,  0x0000(r30)
	add		r27, r27, r29
	subf.	r8, r27, r5
	bge		KCHoldPages_0xec

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall



#     # ######  #     #                                    ######                              
##   ## #     # #     # #    # #    #  ####  #      #####  #     #   ##    ####  ######  ####  
# # # # #     # #     # ##   # #    # #    # #      #    # #     #  #  #  #    # #      #      
#  #  # ######  #     # # #  # ###### #    # #      #    # ######  #    # #      #####   ####  
#     # #       #     # #  # # #    # #    # #      #    # #       ###### #  ### #           # 
#     # #       #     # #   ## #    # #    # #      #    # #       #    # #    # #      #    # 
#     # #        #####  #    # #    #  ####  ###### #####  #       #    #  ####  ######  ####  

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: no

	DeclareMPCall	90, MPUnholdPages

MPUnholdPages

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass

	bne		ReleaseAndReturnMPCallInvalidIDErr
	mr		r31, r8
	add		r5, r5, r4
	lwz		r16, Area.LogicalBase(r31)
	lwz		r17, Area.LogicalEnd(r31)
	addi	r5, r5, -0x01
	cmplw	r4, r16
	cmplw	cr1, r5, r17
	blt		ReleaseAndReturnParamErrFromMPCall
	bgt		cr1, ReleaseAndReturnParamErrFromMPCall
	lwz		r19,  0x0020(r31)
	lwz		r29,  0x0068(r31)
	rlwinm.	r8, r19,  0, 16, 16
	bne		ReleaseAndReturnParamErrFromMPCall
	mr		r27, r4

KCUnholdPages_0x60
	mr		r8, r27
	bl		MPCall_95_0x254
	beq		ReleaseAndReturnParamErrFromMPCall
	lhz		r18,  0x0000(r30)
	clrlwi	r17, r18,  0x18
	rlwinm.	r8, r18,  0, 16, 16
	cmpwi	cr1, r17,  0x00
	beq		major_0x0b0cc
	addi	r28, r28,  0x01
	beq		cr1, major_0x0b0cc
	add		r27, r27, r29
	subf.	r8, r27, r5
	bge		KCUnholdPages_0x60
	li		r28,  0x00

KCUnholdPages_0x98
	mr		r8, r4
	bl		MPCall_95_0x254
	beq		ReleaseAndReturnParamErrFromMPCall
	lhz		r18,  0x0000(r30)
	clrlwi	r17, r18,  0x18
	addi	r17, r17, -0x01
	rlwimi	r18, r17,  0, 24, 31
	clrlwi.	r8, r18,  0x11
	bne		KCUnholdPages_0xc4
	rlwinm	r18, r18,  0, 17, 15
	addi	r28, r28,  0x01

KCUnholdPages_0xc4
	sth		r18,  0x0000(r30)
	add		r4, r4, r29
	subf.	r8, r4, r5
	bge		KCUnholdPages_0x98

	_Lock			PSA.PoolLock, scratch1=r16, scratch2=r17

	lwz		r16, PSA.UnheldFreePageCount(r1)
	add		r16, r16, r28
	stw		r16, PSA.UnheldFreePageCount(r1)
	_AssertAndRelease	PSA.PoolLock, scratch=r16

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall



#     # ######   #####               ######                          #                                                           
##   ## #     # #     # ###### ##### #     #   ##    ####  ######   # #   ##### ##### #####  # #####  #    # ##### ######  ####  
# # # # #     # #       #        #   #     #  #  #  #    # #       #   #    #     #   #    # # #    # #    #   #   #      #      
#  #  # ######  #  #### #####    #   ######  #    # #      #####  #     #   #     #   #    # # #####  #    #   #   #####   ####  
#     # #       #     # #        #   #       ###### #  ### #      #######   #     #   #####  # #    # #    #   #   #           # 
#     # #       #     # #        #   #       #    # #    # #      #     #   #     #   #   #  # #    # #    #   #   #      #    # 
#     # #        #####  ######   #   #       #    #  ####  ###### #     #   #     #   #    # # #####   ####    #   ######  ####  

;	ARG		MPAreaID r3, LogicalPage *r4
;	RET		OSStatus r3, PageAttrs r5

	DeclareMPCall	91, MPGetPageAttributes

MPGetPageAttributes

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass
	bne		ReleaseAndReturnMPCallInvalidIDErr
	mr		r31, r8

	;	Check that the passed address lies within the area
	lwz		r16, Area.LogicalBase(r31)
	lwz		r17, Area.LogicalEnd(r31)
	cmplw	r4, r16
	cmplw	cr1, r4, r17
	blt		ReleaseAndReturnParamErrFromMPCall
	bgt		cr1, ReleaseAndReturnParamErrFromMPCall

	_Lock			PSA.HTABLock, scratch1=r14, scratch2=r15

	;	Find the Page List Entry
	mr		r8, r4
	bl		SpaceGetPagePLE ; LogicalPage *r8, Area *r31 // PLE *r30, notfound cr0.eq
	beq		@release_lock_return_oom

	;	Clear the PTE from the HTAB
	bl		GetPTEFromPLE ; PLE *r30 // PTE r16/r17, PTE *r18, PTEflags cr0, PLEflags cr5-7
	bcl		BO_IF, Area.kPLEFlagIsInHTAB, InvalPTE ; page *r8, PTE r16/r17, PTE *r18, PLE *r30 // PLEflags cr5-7
	bcl		BO_IF, Area.kPLEFlagIsInHTAB, DeletePTE ; PTE *r18, PLE *r30

	;	Get the PLE, and then we're clear of the HTAB lock
	lwz		r29, 0(r30)
	_AssertAndRelease	PSA.HTABLock, scratch=r14

	mr		r8, r4
	bl		MPCall_95_0x254

	li		r19, 0
	beq		@_ac
	lhz		r19, 0(r30)
@_ac

	andi.	r5, r29,  0x319
	rlwinm.	r8, r19,  0, 16, 16
	rlwimi	r5, r19,  0, 16, 16
	beq		ReleaseAndReturnZeroFromMPCall

	rlwinm.	r8, r19,  0, 17, 23
	beq		ReleaseAndReturnZeroFromMPCall

	ori		r5, r5,  0x4000
	b		ReleaseAndReturnZeroFromMPCall

@release_lock_return_oom
	_AssertAndRelease	PSA.HTABLock, scratch=r14
	b		ReleaseAndReturnMPCallOOM



#     # ######   #####               ######                          #                                                           
##   ## #     # #     # ###### ##### #     #   ##    ####  ######   # #   ##### ##### #####  # #####  #    # ##### ######  ####  
# # # # #     # #       #        #   #     #  #  #  #    # #       #   #    #     #   #    # # #    # #    #   #   #      #      
#  #  # ######   #####  #####    #   ######  #    # #      #####  #     #   #     #   #    # # #####  #    #   #   #####   ####  
#     # #             # #        #   #       ###### #  ### #      #######   #     #   #####  # #    # #    #   #   #           # 
#     # #       #     # #        #   #       #    # #    # #      #     #   #     #   #   #  # #    # #    #   #   #      #    # 
#     # #        #####  ######   #   #       #    #  ####  ###### #     #   #     #   #    # # #####   ####    #   ######  ####  

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: no

	DeclareMPCall	92, MPSetPageAttributes

MPSetPageAttributes

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass

	bne		ReleaseAndReturnMPCallInvalidIDErr
	mr		r31, r8
	lwz		r16, Area.Flags(r31)
	rlwinm.	r8, r16,  0, 28, 28
	bne		ReleaseAndReturnParamErrFromMPCall
	lwz		r29,  0x0134(r6)
	li		r8,  0x318
	andc.	r9, r5, r8
	bne		ReleaseAndReturnParamErrFromMPCall
	andc.	r9, r29, r8
	bne		ReleaseAndReturnParamErrFromMPCall
	lwz		r16, Area.LogicalBase(r31)
	lwz		r17, Area.LogicalEnd(r31)
	cmplw	r4, r16
	cmplw	cr1, r4, r17
	blt		ReleaseAndReturnParamErrFromMPCall
	bgt		cr1, ReleaseAndReturnParamErrFromMPCall

	_Lock			PSA.HTABLock, scratch1=r14, scratch2=r15

	mr		r8, r4
	bl		SpaceGetPagePLE ; LogicalPage *r8, Area *r31 // PLE *r30, notfound cr0.eq
	beq		MPCall_92_0xd8
	bl		GetPTEFromPLE ; PLE *r30 // PTE r16/r17, PTE *r18, PTEflags cr0, PLEflags cr5-7
	bc		BO_IF_NOT, Area.kPLEFlagHasPhysPage, MPCall_92_0x9c
	bcl		BO_IF, Area.kPLEFlagIsInHTAB, InvalPTE ; page *r8, PTE r16/r17, PTE *r18, PLE *r30 // PLEflags cr5-7
	bcl		BO_IF, Area.kPLEFlagIsInHTAB, DeletePTE ; PTE *r18, PLE *r30

MPCall_92_0x9c
	lwz		r16,  0x0000(r30)
	and		r8, r5, r29
	orc		r9, r5, r29
	or		r16, r16, r8
	and		r16, r16, r9
	stw		r16,  0x0000(r30)
	_AssertAndRelease	PSA.HTABLock, scratch=r14

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall

MPCall_92_0xd8
	_AssertAndRelease	PSA.HTABLock, scratch=r14
	b		ReleaseAndReturnMPCallOOM



#     # ######   #####               ######                          #                  
##   ## #     # #     # ###### ##### #     #   ##    ####  ######   # #    ####  ###### 
# # # # #     # #       #        #   #     #  #  #  #    # #       #   #  #    # #      
#  #  # ######  #  #### #####    #   ######  #    # #      #####  #     # #      #####  
#     # #       #     # #        #   #       ###### #  ### #      ####### #  ### #      
#     # #       #     # #        #   #       #    # #    # #      #     # #    # #      
#     # #        #####  ######   #   #       #    #  ####  ###### #     #  ####  ###### 

;	Straight MPLibrary wrapper: returns value via passed ptr
;	In Universal Interfaces: no

	DeclareMPCall	93, MPGetPageAge

MPGetPageAge

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass

	bne		ReleaseAndReturnMPCallInvalidIDErr
	mr		r31, r8
	lwz		r16, Area.LogicalBase(r31)
	lwz		r17, Area.LogicalEnd(r31)
	cmplw	r4, r16
	cmplw	cr1, r4, r17
	blt		ReleaseAndReturnParamErrFromMPCall
	bgt		cr1, ReleaseAndReturnParamErrFromMPCall
	mr		r8, r4
	bl		MPCall_95_0x254
	beq		ReleaseAndReturnParamErrFromMPCall
	lhz		r18,  0x0000(r30)
	rlwinm.	r8, r18,  0, 16, 16
	li		r5,  0x00

;	r1 = kdp
	bne		ReleaseAndReturnZeroFromMPCall
	clrlwi	r5, r18,  0x11

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall



#     # ######   #####               ######                          #                  
##   ## #     # #     # ###### ##### #     #   ##    ####  ######   # #    ####  ###### 
# # # # #     # #       #        #   #     #  #  #  #    # #       #   #  #    # #      
#  #  # ######   #####  #####    #   ######  #    # #      #####  #     # #      #####  
#     # #             # #        #   #       ###### #  ### #      ####### #  ### #      
#     # #       #     # #        #   #       #    # #    # #      #     # #    # #      
#     # #        #####  ######   #   #       #    #  ####  ###### #     #  ####  ###### 

;	Straight MPLibrary wrapper: yes
;	In Universal Interfaces: no

	DeclareMPCall	94, MPSetPageAge

MPSetPageAge

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass

	bne		ReleaseAndReturnMPCallInvalidIDErr
	mr		r31, r8
	lwz		r16, Area.LogicalBase(r31)
	lwz		r17, Area.LogicalEnd(r31)
	cmplw	r4, r16
	cmplw	cr1, r4, r17
	blt		ReleaseAndReturnParamErrFromMPCall
	bgt		cr1, ReleaseAndReturnParamErrFromMPCall
	mr		r8, r4
	bl		MPCall_95_0x254
	beq		ReleaseAndReturnParamErrFromMPCall
	cmplwi	r5,  0x7fff
	bgt		ReleaseAndReturnParamErrFromMPCall
	lhz		r18,  0x0000(r30)
	rlwinm.	r8, r18,  0, 16, 16
	bne		ReleaseAndReturnMPCallOOM
	rlwimi	r18, r5,  0, 17, 31
	sth		r18,  0x0000(r30)

	_Lock			PSA.HTABLock, scratch1=r16, scratch2=r17

	mr		r8, r4
	bl		SpaceGetPagePLE ; LogicalPage *r8, Area *r31 // PLE *r30, notfound cr0.eq
	beq		SpacePanicIsland
	bl		GetPTEFromPLE ; PLE *r30 // PTE r16/r17, PTE *r18, PTEflags cr0, PLEflags cr5-7
	bc		BO_IF_NOT, Area.kPLEFlagHasPhysPage, MPCall_94_0xa0
	bcl		BO_IF, Area.kPLEFlagIsInHTAB, InvalPTE ; page *r8, PTE r16/r17, PTE *r18, PLE *r30 // PLEflags cr5-7
	bcl		BO_IF, Area.kPLEFlagIsInHTAB, DeletePTE ; PTE *r18, PLE *r30

MPCall_94_0xa0
	_AssertAndRelease	PSA.HTABLock, scratch=r16

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall



#     # ######   #####               ######                       #     #                      #                             #####                                    
##   ## #     # #     # ###### ##### #     #   ##    ####  ###### #     #  ####  #      #####  #        ####   ####  #    # #     #  ####  #    # #    # #####  ####  
# # # # #     # #       #        #   #     #  #  #  #    # #      #     # #    # #      #    # #       #    # #    # #   #  #       #    # #    # ##   #   #   #      
#  #  # ######  #  #### #####    #   ######  #    # #      #####  ####### #    # #      #    # #       #    # #      ####   #       #    # #    # # #  #   #    ####  
#     # #       #     # #        #   #       ###### #  ### #      #     # #    # #      #    # #       #    # #      #  #   #       #    # #    # #  # #   #        # 
#     # #       #     # #        #   #       #    # #    # #      #     # #    # #      #    # #       #    # #    # #   #  #     # #    # #    # #   ##   #   #    # 
#     # #        #####  ######   #   #       #    #  ####  ###### #     #  ####  ###### #####  #######  ####   ####  #    #  #####   ####   ####  #    #   #    ####  

;	Straight MPLibrary wrapper: returns value via passed ptr
;	In Universal Interfaces: no

	DeclareMPCall	129, MPGetPageHoldLockCounts

MPGetPageHoldLockCounts

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	mr		r8, r3
 	bl		LookupID
	cmpwi	r9, Area.kIDClass

	bne		ReleaseAndReturnMPCallInvalidIDErr
	mr		r31, r8
	lwz		r16, Area.LogicalBase(r31)
	lwz		r17, Area.LogicalEnd(r31)
	cmplw	r4, r16
	cmplw	cr1, r4, r17
	blt		ReleaseAndReturnParamErrFromMPCall
	bgt		cr1, ReleaseAndReturnParamErrFromMPCall
	mr		r8, r4
	bl		MPCall_95_0x254
	beq		ReleaseAndReturnParamErrFromMPCall
	lhz		r18,  0x0000(r30)
	li		r5,  0x00
	rlwinm.	r8, r18,  0, 16, 16
	li		r16,  0x00
	beq		MPCall_129_0x6c
	rlwinm	r16, r18, 24, 25, 31
	clrlwi	r5, r18,  0x18

MPCall_129_0x6c
	stw		r16,  0x0134(r6)

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall



#     # ######  #######                 #     #                         ######                       
##   ## #     # #       # #    # #####  #     # #  ####  ##### # #    # #     #   ##    ####  ###### 
# # # # #     # #       # ##   # #    # #     # # #    #   #   # ##  ## #     #  #  #  #    # #      
#  #  # ######  #####   # # #  # #    # #     # # #        #   # # ## # ######  #    # #      #####  
#     # #       #       # #  # # #    #  #   #  # #        #   # #    # #       ###### #  ### #      
#     # #       #       # #   ## #    #   # #   # #    #   #   # #    # #       #    # #    # #      
#     # #       #       # #    # #####     #    #  ####    #   # #    # #       #    #  ####  ###### 

;	Straight MPLibrary wrapper: returns value via passed ptr
;	In Universal Interfaces: no

	DeclareMPCall	95, MPFindVictimPage

MPFindVictimPage

	or.		r8, r3, r4

	bne		@not_naughty
	li		r16, 0
	stw		r16, KDP.VMMaxVirtualPages(r1)
	_log	'Areas capability probe detected^n'
	b		ReturnParamErrFromMPCall
@not_naughty

	_Lock			PSA.SchLock, scratch1=r16, scratch2=r17

	li		r28, -0x01
	li		r4,  0x00
	li		r5,  0x00
	lwz		r8, PSA.UnheldFreePageCount(r1)
	cmpwi	r8,  0x00
	ble		ReleaseAndReturnMPCallOOM
	lwz		r27, PSA.DecClockRateHzCopy(r1)
	srwi	r27, r27, 15
	mfspr	r8, dec
	subf	r27, r27, r8
	lwz		r8, PSA.OtherSystemAddrSpcPtr2(r1)
	lwz		r9, PSA.ZeroedByInitFreeList3(r1)
	mr		r30, r9
	bl		FindAreaAbove
	mr		r31, r8
	lwz		r29, Area.LogicalBase(r31)
	cmplw	r29, r30
	bgt		MPCall_95_0xa8
	mr		r29, r30

MPCall_95_0xa8
	crset	cr2_eq

MPCall_95_0xac
	mfspr	r9, dec
	subf.	r9, r27, r9
	blt		MPCall_95_0x1c8

MPCall_95_0xb8
	lwz		r8,  0x0020(r31)
	lwz		r9,  0x0018(r31)
	rlwinm.	r8, r8,  0, 16, 16
	cmpwi	cr1, r3,  0x00
	bne		MPCall_95_0x19c
	beq		cr1, MPCall_95_0xe0
	cmpwi	cr3, r9,  0x00
	beq		cr3, MPCall_95_0xe0
	cmpw	cr1, r9, r3
	bne		cr1, MPCall_95_0x19c

MPCall_95_0xe0
	lwz		r9, Area.Flags(r31)
	rlwinm.	r8, r9,  0, 28, 28
	bne		MPCall_95_0x19c
	rlwinm.	r8, r9,  0, 23, 23
	bne		MPCall_95_0x19c

	_Lock			PSA.HTABLock, scratch1=r16, scratch2=r17

	mr		r8, r29
	bl		SpaceGetPagePLE ; LogicalPage *r8, Area *r31 // PLE *r30, notfound cr0.eq
	beq		SpacePanicIsland
	_AssertAndRelease	PSA.HTABLock, scratch=r16
	lwz		r16,  0x0000(r30)
	clrlwi.	r8, r16,  0x1f
	beq		MPCall_95_0x180
	mr		r8, r29
	bl		MPCall_95_0x254
	beq		MPCall_95_0x1c8
	lhz		r17,  0x0000(r30)
	rlwinm.	r8, r17,  0, 16, 16
	clrlwi	r17, r17,  0x11
	bne		MPCall_95_0x180
	cmpw	r17, r28
	crclr	cr2_eq
	ble		MPCall_95_0x180
	mr		r28, r17
	lwz		r4, Area.ID(r31)
	cmplwi	r17,  0x7fff
	mr		r5, r29
	bge		MPCall_95_0x1c8

MPCall_95_0x180
	lwz		r8,  0x0068(r31)
	lwz		r9, Area.LogicalEnd(r31)
	add		r29, r29, r8
	subf.	r9, r9, r29
	bge		MPCall_95_0x19c
	bne		cr2, MPCall_95_0xac
	b		MPCall_95_0xb8

MPCall_95_0x19c
	lwz		r8,  0x0054(r31)
	lwz		r9,  0x005c(r31)
	cmpw	r8, r9
	addi	r31, r9, -0x54
	lwz		r29, Area.LogicalBase(r31)
	bne		MPCall_95_0x1c0
	lwz		r9,  0x0008(r8)
	addi	r31, r9, -0x54
	lwz		r29, Area.LogicalBase(r31)

MPCall_95_0x1c0
	bne		cr2, MPCall_95_0xac
	b		MPCall_95_0xb8

MPCall_95_0x1c8
	cmpwi	r4,  0x00
	stw		r29, PSA.ZeroedByInitFreeList3(r1)
	beq		ReleaseAndReturnMPCallOOM
	lwz		r8,  0x0068(r31)
	add		r8, r8, r5
	stw		r8, PSA.ZeroedByInitFreeList3(r1)

;	r1 = kdp
	b		ReleaseAndReturnZeroFromMPCall



 #####                               #####               ######                       ######  #       ####### 
#     # #####    ##    ####  ###### #     # ###### ##### #     #   ##    ####  ###### #     # #       #       
#       #    #  #  #  #    # #      #       #        #   #     #  #  #  #    # #      #     # #       #       
 #####  #    # #    # #      #####  #  #### #####    #   ######  #    # #      #####  ######  #       #####   
      # #####  ###### #      #      #     # #        #   #       ###### #  ### #      #       #       #       
#     # #      #    # #    # #      #     # #        #   #       #    # #    # #      #       #       #       
 #####  #      #    #  ####  ######  #####  ######   #   #       #    #  ####  ###### #       ####### ####### 

SpaceGetPagePLE ; LogicalPage *r8, Area *r31 // PLE *r30, notfound cr0.eq

	lwz		r16, Area.LogicalBase(r31)
	lwz		r18, Area.Flags(r31)
	lwz		r30, Area.PageMapArrayPtr(r31)

	;	r17 = offset of ptr into area
	subf	r17, r16, r8

@loop_that_would_totally_happen_but_not

	;	Fail if Area has no page map array.
	;	r17 = offset of page's entry in page map (entries are 4b)
	cmpwi	r30, 0
	rlwinm	r17, r17, (32-10), 10, 29
	beqlr

	;	Do another level of lookups if the array is 2D
	;	(i.e. the Area contains more than 1k pages)
	rlwinm.	r16, r18,  0, Area.kPageMapArrayIs2D, Area.kPageMapArrayIs2D
	rlwinm	r16, r17, (32-10), 20, 29		; offset of secondary ptr in page map
	beq		@not_2d
	rlwinm	r17, r17,  0, 20, 29
	lwzx	r30, r30, r16
@not_2d

	;	Return r30, a pointer to the list entry
	;	cr0.eq if we failed
	add.	r30, r30, r17
	blr

	;	Dead code:
	lwz		r16, Area.LogicalBase(r31)
	lwz		r18, Area.Flags(r31)
	lwz		r30,  0x0040(r31)

	rlwinm.	r17, r18, 0, Area.kAliasFlag, Area.kAliasFlag
	subf	r17, r16, r8
	beq		@loop_that_would_totally_happen_but_not

	lwz		r30, Area.AliasLLL(r31)
	lwz		r18, 0x80(r31)
	subi	r30, r30, Area.AliasLLL
	subf	r17, r16, r8
	add		r17, r17, r18
	lwz		r18, Area.Flags(r30)
	lwz		r30, Area.PageMapArrayPtr(r30)
	b		@loop_that_would_totally_happen_but_not



MPCall_95_0x254	;	OUTSIDE REFERER
	lwz		r16, Area.LogicalBase(r31)
	lwz		r18, Area.Flags(r31)
	lwz		r30,  0x003c(r31)
	rlwinm.	r17, r18,  0, Area.kAliasFlag, Area.kAliasFlag
	subf	r17, r16, r8
	beq		MPCall_95_0x288

	lwz		r30,  0x0044(r31)
	lwz		r18,  0x0080(r31)
	addi	r30, r30, -0x44
	subf	r17, r16, r8
	add		r17, r17, r18
	lwz		r18,  0x0008(r30)
	lwz		r30,  0x003c(r30)

MPCall_95_0x288
	cmpwi	r30,  0x00
	rlwinm	r17, r17, 21, 11, 30
	beqlr
	rlwinm.	r16, r18,  0, 30, 30
	rlwinm	r16, r17, 22, 20, 29
	beq		MPCall_95_0x2a8
	rlwinm	r17, r17,  0, 20, 30
	lwzx	r30, r30, r16

MPCall_95_0x2a8
	add.	r30, r30, r17
	blr



 #####               ######  ####### ####### #######                      ######  #       ####### 
#     # ###### ##### #     #    #    #       #       #####   ####  #    # #     # #       #       
#       #        #   #     #    #    #       #       #    # #    # ##  ## #     # #       #       
#  #### #####    #   ######     #    #####   #####   #    # #    # # ## # ######  #       #####   
#     # #        #   #          #    #       #       #####  #    # #    # #       #       #       
#     # #        #   #          #    #       #       #   #  #    # #    # #       #       #       
 #####  ######   #   #          #    ####### #       #    #  ####  #    # #       ####### ####### 

;	If a logical page (of an Area of an AddressSpace) is featured in the HTAB,
;	its NanoKernel Page List Entry (PLE) should point at that PowerPC Page Table
;	Entry (PTE, of a PTEG in the HTAB). If there is a physical page mapped to
;	that logical page, but it is not yet in the HTAB, then the PLE will point
;	directly to the page.

GetPTEFromPLE ; PLE *r30 // PTE r16/r17, PTE *r18, PTEflags cr0, PLEflags cr5-7

	lwz		r19, 0(r30)						; r19 = contents of page list entry
	lwz		r18, KDP.HTABORG(r1)			; r18 = HTAB base, in case like me you were confused

	mtcrf	%00000111, r19					; cr5-7 = flags from PLE

	;	Returning early because we are not in HTAB? Cook up a fake PTE.
	rlwinm	r17, r19, 0, 0, 19				; lower has RPN
	rlwinm	r16, r19, (32-9), 0+9, 19+9		; will actually use this as PTE offset within HTAB!

	bclr	BO_IF_NOT, Area.kPLEFlagHasPhysPage
	bclr	BO_IF_NOT, Area.kPLEFlagIsInHTAB

	;	r16/r17 = PTE
	;	r18 = &PTE
	lwzux	r16, r18, r16
	lwz		r17, 4(r18)

	;	Die if V bit is not set (entry is invalid).
	;	Return flags.
	mtcrf	%10000000, r16
	bc		BO_IF_NOT, 0, SpacePanicIsland

	blr



###                             ######  ####### ####### 
 #  #    # #    #   ##   #      #     #    #    #       
 #  ##   # #    #  #  #  #      #     #    #    #       
 #  # #  # #    # #    # #      ######     #    #####   
 #  #  # # #    # ###### #      #          #    #       
 #  #   ##  #  #  #    # #      #          #    #       
### #    #   ##   #    # ###### #          #    ####### 

InvalPTE ; page *r8, PTE r16/r17, PTE *r18, PLE *r30 // PLEflags cr5-7

	;	Special-case 601.
	;	Clear V bit of PTE.
	mfspr	r14, pvr
	_bclr	r16, r16, 0
	rlwinm.	r14, r14, 0, 0xFFFE0000
	stw		r16, 0(r18)

	;	Now that HTAB is touched, bump our page from the TLB
	sync
	tlbie	r8
	beq		@is_601
	sync
	tlbsync
@is_601
	sync
	isync

	;	Prepare to re-set V bit, but return if there is no PLE
	cmpwi	r30, 0

	;	Be needlessly sure that these registers don't get clobbered
	lwz		r14, 0(r30)				; r14 = PLE
	lwz		r17, 4(r18)				; r17 = lower PTE
	_bset	r16, r16, 0				; r16 = upper PTE

	beqlr

	;	Continue if there is a PLE involved... INTERESTING PART
	rlwimi	r14, r17, (32-3), 27, 27		; lowest two bits of VSID into 27/28 of PLE
	rlwimi	r14, r17, (32-5), 28, 28

	;	Slightly update the cond reg with the new PLE
	;	(flags 27 and 28, others should be unchanged)
	mtcrf	%00000111, r14			; set CR (is return value)
	stw		r14, 0(r30)				; save that PLE

	blr



 #####               ######  ####### ####### 
#     # ###### ##### #     #    #    #       
#       #        #   #     #    #    #       
 #####  #####    #   ######     #    #####   
      # #        #   #          #    #       
#     # #        #   #          #    #       
 #####  ######   #   #          #    ####### 

SetPTE ; PTE r16/r17, PTE *r18

	stw		r17, 4(r18)
	eieio
	stw		r16, 0(r18)
	sync
	blr



######                                    ######  ####### ####### 
#     # ###### #      ###### ##### ###### #     #    #    #       
#     # #      #      #        #   #      #     #    #    #       
#     # #####  #      #####    #   #####  ######     #    #####   
#     # #      #      #        #   #      #          #    #       
#     # #      #      #        #   #      #          #    #       
######  ###### ###### ######   #   ###### #          #    ####### 

DeletePTE ; PTE *r18, PLE *r30

	lwz		r14, 0(r30)

	_InvalNCBPointerCache scratch=r16

foo set KDP.NanoKernelInfo + NKNanoKernelInfo.HashTableDeleteCount
	lwz		r16, foo(r1)
	_bclr	r14, r14, Area.kPLEFlagIsInHTAB
	addi	r16, r16, 1
	stw		r16, foo(r1)

	;	Change "PLE>PTE>page" to "PLE>page"
	rlwimi	r14, r17, 0, 0xfffff000

	;	Fully zero the PTE.
	;	But only zero the PLE if the ptr is non-null.
	cmpwi	r30, 0
	li		r16, 0
	li		r17, 0
	beq		SetPTE ; PTE r16/r17, PTE *r18
	stw		r14, 0(r30)
	b		SetPTE ; PTE r16/r17, PTE *r18



 #####                              #        #####  ######  #     #                        ######     #    #######        
#     # #####    ##    ####  ###### #       #     # #     # #     #  ####  # #    #  ####  #     #   # #      #     ####  
#       #    #  #  #  #    # #      #             # #     # #     # #      # ##   # #    # #     #  #   #     #    #      
 #####  #    # #    # #      #####  #        #####  ######  #     #  ####  # # #  # #      ######  #     #    #     ####  
      # #####  ###### #      #      #       #       #       #     #      # # #  # # #  ### #     # #######    #         # 
#     # #      #    # #    # #      #       #       #       #     # #    # # #   ## #    # #     # #     #    #    #    # 
 #####  #      #    #  ####  ###### ####### ####### #        #####   ####  # #    #  ####  ######  #     #    #     ####  

SpaceL2PUsingBATs ; LogicalPage *r8, MPAddressSpace *r9 // PhysicalPage *r17

	MACRO
	_v2pguts 						; cr0.eq = match
	rlwimi	r19, r16, 15, 0, 14		; r19 = 0000 (4b) || BEPI (11b) || 11111111111111111 (17b) = bits that needn't match
	xor		r17, r8, r16			; xor the two things we are comparing
	andc.	r17, r17, r19			; mask away the bits that needn't match
	ENDM


	;	Use current Address Space if none specified

	mr.		r19, r9
	mfsprg	r17, 0
	bne		@addrspc_provided
	lwz		r19, EWA.PA_CurAddressSpace(r17)
@addrspc_provided


	;	Search all 8 UBAT registers for one that contains our effective address

	addi	r18, r19, AddressSpace.BATs

	lwz		r16, 0(r18)
	li		r19, -1
	_v2pguts
	beq		@bat_yes

	lwzu	r16, 8(r18)
	_v2pguts
	beq		@bat_yes

	lwzu	r16, 8(r18)
	_v2pguts
	beq		@bat_yes

	lwzu	r16, 8(r18)
	_v2pguts
	beq		@bat_yes

	lwzu	r16, 8(r18)
	_v2pguts
	beq		@bat_yes

	lwzu	r16, 8(r18)
	_v2pguts
	beq		@bat_yes

	lwzu	r16, 8(r18)
	_v2pguts
	beq		@bat_yes

	lwzu	r16, 8(r18)
	_v2pguts
	bne		@bat_no

@bat_yes
	andi.	r17, r16, 1						; cr0.eq = !UBAT[Vp]
	rlwinm	r19, r19, 0, 8, 19
	lwzu	r17, 4(r18)						; r17 = LBAT
	and		r19, r8, r19
	or		r17, r17, r19
	bnelr									; succeed if UBAT[Vp] is set

@bat_no



 #####                              #        #####  ######  ###                                             ######     #    #######        
#     # #####    ##    ####  ###### #       #     # #     #  #   ####  #    #  ####  #####  # #    #  ####  #     #   # #      #     ####  
#       #    #  #  #  #    # #      #             # #     #  #  #    # ##   # #    # #    # # ##   # #    # #     #  #   #     #    #      
 #####  #    # #    # #      #####  #        #####  ######   #  #      # #  # #    # #    # # # #  # #      ######  #     #    #     ####  
      # #####  ###### #      #      #       #       #        #  #  ### #  # # #    # #####  # #  # # #  ### #     # #######    #         # 
#     # #      #    # #    # #      #       #       #        #  #    # #   ## #    # #   #  # #   ## #    # #     # #     #    #    #    # 
 #####  #      #    #  ####  ###### ####### ####### #       ###  ####  #    #  ####  #    # # #    #  ####  ######  #     #    #     ####  

SpaceL2PIgnoringBATs ; LogicalPage *r8, MPAddressSpace *r9 // PhysicalPage *r17

	;	r17 = segment descriptor (from addrspc or actual register)

	cmpwi	r9, 0
	addi	r16, r9, AddressSpace.SRs
	beq		@no_addrspc_provided

;addrspc provided
	rlwinm	r17, r8, (32-26), 26, 29
	lwzx	r17, r16, r17
	b		@endif_addrspc

@no_addrspc_provided
	mfsrin	r17, r8

@endif_addrspc


	;	Do the "(VSID || page index) -> PTEG address" hashing function
	;	Remember, PTEG = 8 x 8b PTEs

	;	r18 = physical address of 64b PTEG to search
	;	r16 = upper PTE to check for (V, VSID and API fields)

	rlwinm	r16, r8, 10, 26, 31			; set API field of r16
	rlwimi	r16, r17, 7, 1, 24			; set VSID field of r16
	rlwinm	r9, r8, 32-6, 10, 25		; r9 = page index in bits 0x003FFFC0
	_bset	r16, r16, 0					; set V(alid) bit of r16 to 1
	rlwinm	r17, r17, 6, 7, 25
	xor		r9, r9, r17					; r9 ^= (VSID & 0x7FFFF) in bits 0x01FFFFC0

	lwz		r17, KDP.PTEGMask(r1)
	lwz		r18, KDP.HTABORG(r1)

	and		r9, r9, r17					; r9 %= HTAB size
	or.		r18, r18, r9				; r18 = &HTAB + r9 = &PTEG


	;	This is tightly coded, but is obviously searching the PTEG for a match with r16

@try_other_four_PTEs
	lwz		r17, 0*8(r18)				; load this upper PTE
	lwz		r9, 1*8(r18)				; and the next upper PTE
	cmpw	cr6, r16, r17
	lwz		r17, 2*8(r18)				; and the next upper PTE
	cmpw	cr7, r16, r9
	lwzu	r9, 3*8(r18)				; and the next upper PTE, and update

	bne		cr6, @nope

@yes_this_one
	lwzu	r17, -20(r18)
	blr

@nope
	cmpw	cr6, r16, r17
	lwzu	r17, 8(r18)
	beq		cr7, @yes_this_one

	cmpw	cr7, r16, r9
	lwzu	r9, 8(r18)
	beq		cr6, @yes_this_one

	cmpw	cr6, r16, r17
	lwzu	r17, 8(r18)
	beq		cr7, @yes_this_one

	cmpw	cr7, r16, r9
	lwzu	r9, 8(r18)
	beq		cr6, @yes_this_one

	cmpw	cr6, r16, r17
	lwzu	r17, -12(r18)
	beqlr	cr7

	cmpw	cr7, r16, r9
	lwzu	r17, 8(r18)
	beqlr	cr6

	lwzu	r17, 8(r18)
	beqlr	cr7

	lwz		r17, KDP.PTEGMask(r1)

	xori	r16, r16, 0x40				; try the other four PTEs in this PTEG
	andi.	r9, r16, 0x40				; but if that bit went back to 0 from 1 then we're out of PTEs!

	addi	r18, r18, -0x3c
	xor		r18, r18, r17

	bne		@try_other_four_PTEs

	blr									; fail
