; TITLE: Source code for Bryce's Deadly Memory Munger (with enhancements)
;
; Bryce's deadly memory munger
;
; Munge2: Enhancements by Joe Pearce
;
; Wipes all free (unused) memory at program startup to $01.
; Also, wipes memory just before FreeMem().
;
; If run from CLI, use "break" to kill it off.
; Use "break # d" to toggle between setting freed memory to 1's (the
; default) and clearing to zero instead.
; Use "break # e" to force munge to "remunge" all of memory.
; Use "break # f" to toggle on/off state.
;
; If run from the workbench, run it again to kill it.
;
; Control of munge can be done from another program as shown:
;	port = FindPort("munge.port");
;	if (port) Signal(port->mp_SigTask,signal#);
;
; You can check the state of the munger by checking the WORD after the port
; in memory. Bit 0 set indicated munging to zero. Bit 1 set indicates
; munger off. For example:
;	WORD state;
;	state = *((WORD *)port + sizeof(struct MsgPort) / 2);
;	if (state & 1) puts("Munging to zero.");
;	if (state & 2) puts("Munger off");
;
; This is a very crude hack... breaks all the rules.
;
; Sorry it does not pinpoint your bug.	They never said finding
; bugs was easy. :-)
;
; This source doesn't have "CloseLock" commented out.
;
; Note from Joe: If the symbol MUNGELAYER is defined, munge will catch the
; "layers library bug" at a lower level than CloseWindow. This works until
; munge is exited at which time Intuition acts very strange and eventually
; crashes. Therefore, if you want to munge at the layer level, I suggest
; you turn off munge with a CTRL_F signal instead of terminating it.
; Running SetPatch (from WB1.3) on your system fixes the layer bug.
; Define the symbol PATCHED to remove all bug handling by munge.
;
; Assembly note for Manx users (from Joe):
;	as -n -c -d (-eMUNGELAYER) (-ePATCHED) munge2.asm
;	ln munge2.o -lc32 (although -lc might work just as well)
;
	NOLIST
	INCLUDE "exec/types.i"
	INCLUDE "exec/lists.i"
	INCLUDE "exec/execbase.i"
	INCLUDE "exec/memory.i"
	INCLUDE "exec/ables.i"
	INCLUDE "exec/ports.i"
	INCLUDE "exec/alerts.i"
	INCLUDE "libraries/dos.i"
	INCLUDE "libraries/dosextens.i"
	LIST

ANY_CTRL equ SIGBREAKF_CTRL_C+SIGBREAKF_CTRL_D+SIGBREAKF_CTRL_E+SIGBREAKF_CTRL_F

jsrlib	MACRO
		xref _LVO\1
		jsr  _LVO\1(a6)
		ENDM

jmplib	MACRO
		xref _LVO\1
		jmp  _LVO\1(a6)
		ENDM

blink	MACRO
		bchg.b	#1,$bfe001
		ENDM

*********************************************
		entry	start			; comment this out for Metacomco (?)

start	move.l	4,a6		    ;Get exec library pointer
		suba.l	a1,a1		    ;Put zero in A1
		jsrlib	FindTask	    ;Find this task
		move.l	d0,a5
		move.l	pr_ReturnAddr(a5),a0
		move.l	(a0),d7             ;---Get stack size--

		moveq	#0,d0		    ;Set zero for later
		move.l	pr_CLI(a5),d1       ;Check CLI/Workbench flag
		bne.s	fromCLI

		lea.l	pr_MsgPort(a5),a0   ;Wait for the message
		jsrlib	WaitPort	    ; the Workbench will send
		lea.l	pr_MsgPort(a5),a0
		jsrlib	GetMsg

fromCLI 	move.l	d0,-(a7)            ;Save the message, or zero
******************************************  A5-This task D7-Stack size
		bsr.s	main
******************************************  D7-MUST contain result code
ExitToDOS:	move.l	(a7)+,d2
		beq.s	notWorkbench

		jsrlib	Forbid	    ;Required so we won't be unloaded by
		move.l	d2,a1	    ; the Workbench too soon.
		jsrlib	ReplyMsg    ;Reply to the Workbench message

notWorkbench	move.l	d7,d0	    ;Return result code:
		rts		    ; 0 = ok	   10 = error
				    ; 5 = warning  20 = severe failure
*********************************************

main	lea		MungeName(pc),a1		; find MungePort of existing copy
		jsrlib	FindPort
		tst.l	d0
		beq.s	new						; is none, so install ourselves

		move.l	4,a6
		move.l	d0,a1
		move.l	MP_SIGTASK(a1),a1
		move.l	#SIGBREAKF_CTRL_C,d0	; signal other copy to terminate
		jsrlib	Signal

		moveq	#5,d7					; warning, you just turned us off
		rts								; and exit outselves

new		move.l	4,a6
		move.l	a5,MungePort+MP_SIGTASK ; create a port to declare we're here
		lea		MungePort(pc),a1
		jsrlib	AddPort

		move.l	4,a6

	ifnd	MUNGELAYER
	ifnd	PATCHED
		lea.l	IntuiName(pc),a1
		jsrlib	OldOpenLibrary	; OldOpenLibrary(lib) <-> OpenLibrary(lib,0)
		move.l	d0,IntuiBase
	endc
	else
		lea.l	LayersName(pc),a1
		jsrlib	OldOpenLibrary
		move.l	d0,LayersBase
	endc

		bsr		dofree					; new

	ifnd	MUNGELAYER
	ifnd	PATCHED
		move.l	IntuiBase(pc),a1		;get IntuiBase
		lea.l	MyCloseWindow(pc),a0
		move.l	a0,d0
		move.w	#$ffb8,a0
		jsrlib	SetFunction
		move.l	d0,OldCloseWindow
	endc
	else
		move.l	LayersBase(pc),a1		;get LayersBase
		lea.l	MyDeleteLayer(pc),a0
		move.l	a0,d0
		move.w	#$ffa6,a0
		jsrlib	SetFunction
		move.l	d0,OldDeleteLayer
	endc

		move.l	a6,a1
		lea.l	MyFreeMem(pc),a0		;patch into FreeMem
		move.l	a0,d0
		move.w	#$ff2e,a0
		jsrlib	SetFunction
		move.l	d0,OldFreeMem

; new mode switching

wloop	move.l	#ANY_CTRL,d0
		jsrlib	Wait
		btst.l	#SIGBREAKB_CTRL_C,d0
		bne.s	bye

		btst.l	#SIGBREAKB_CTRL_F,d0
		beq.s	ddd
		bchg.b	#0,OnOff				; toggle on/off state
		bchg.b	#1,MungeState+1

ddd		btst.l	#SIGBREAKB_CTRL_D,d0
		beq.s	eee
		tst.l	MungeVal
		beq.s	doff

		move.l	#0,MungeVal
		bra.s	don

doff	move.l	#$01010101,MungeVal
don		bchg.b	#0,MungeState+1

		tst.b	OnOff
		beq.s	eee

		FORBID
		move.l	d0,-(sp)
		bsr		infree
		move.l	(sp)+,d0

eee		btst.l	#SIGBREAKB_CTRL_E,d0
		beq.s	wloop
		tst.b	OnOff
		beq.s	wloop

		FORBID
		bsr		infree
		bra.s	wloop

bye		move.l	4,a6
		move.l	OldFreeMem(pc),d0
		move.w	#$ff2e,a0
		move.l	a6,a1
		jsrlib	SetFunction

	ifnd	MUNGELAYER
	ifnd	PATCHED
		move.l	OldCloseWindow(pc),d0
		move.w	#$ffb8,a0
		move.l	IntuiBase(pc),a1
		jsrlib	SetFunction
	endc
	else
		move.l	OldDeleteLayer(pc),d0
		move.w	#$ffa6,a0
		move.l	LayersBase(pc),a1
		jsrlib	SetFunction
	endc

		lea		MungePort(pc),a1
		jsrlib	RemPort

		moveq	#0,d7
		rts

dofree
		FORBID
infree
		movem.l	a2/a3,-(sp)
		move.l	MemList+LH_HEAD(a6),a2	; get First MemHeader address

mloop	tst.l	LN_SUCC(a2)				; are we at list end?
		beq.s	mend					; yes, end of mem "clear"

		move.l	MH_FIRST(a2),a3			; First MemChunk
zloop	move.l	MC_BYTES(a3),d0			; get size
		subq.l	#8,d0					; subtract chunk info size
		beq.s	noclear					; can't zap any memory in chunk

		move.l	a3,a1					; calculate first address to clear
		addq.w	#8,a1					; (size already in d0)
		bsr		zapmem

noclear move.l	MC_NEXT(a3),a3
		move.l	a3,d0
		bne.s	zloop

		move.l	LN_SUCC(a2),a2
		move.l	a2,d0
		bra.s	mloop
		
mend	jsrlib	Permit
		movem.l	(sp)+,a2/a3
		rts

; Bryce's

;ff2e  d2 -210 FreeMem(memoryBlock,byteSize)(A1,D0)
;
MyFreeMem	
		tst.b	OnOff
		beq.s	freeoff

		move.l	4,a0
		move.w	#$444,d1	;Grey
		tst.b	$127(a0)        ;Are we Forbid()en?
		bge.s	oldway
		tst.b	$126(a0)        ;Are we Disabled()ed?
		bge.s	oldway

		move.b	$127(a0),$100
		move.w	#$ff0,d1	;Yellow
		tst.l	CloseLock	;Called from within CloseWindow?
		beq.s	noprob		;no...

oldway	blink
		move.w	d1,$dff180
freeoff
		move.l	OldFreeMem(pc),-(a7)
		rts

;Zap block before freeing.
;
noprob	move.w	#$f00,$dff180
		;blink
		bsr.s	zapmem
		move.w	#$05a,$dff180
		move.l	OldFreeMem(pc),-(a7)
		rts

zapmem  ; addr in a1, # bytes to zap in d0, scratch d1
		addq.l	#3,d0			; calc number of longwords
		lsr.l	#2,d0
		move.l	MungeVal,d1		; Wipe memory to this value
		movem.l d0/a1,-(a7)
		bra.s	inlp
loop	move.l	d1,(a1)+
inlp	dbra	d0,loop
		sub.l	#$10000,d0
		bpl.s	loop
		movem.l (a7)+,a1/d0
		rts


	ifnd	MUNGELAYER
	ifnd	PATCHED

;ffb8  48  -72 CloseWindow(Window)(A0)
;
MyCloseWindow
		addq.l	#1,CloseLock
		move.l	a1,-(a7)
		move.l	OldCloseWindow(pc),a1
		jsr	(a1)
		move.l	(a7)+,a1
		subq.l	#1,CloseLock
		rts

	endc
	else

;ffa6  5a  -90 DeleteLayer(LayerInfo,Layer)(A0/A1)
;
MyDeleteLayer
		addq.l	#1,CloseLock
		move.l	a2,-(a7)
		move.l	OldDeleteLayer(pc),a2
		jsr	(a2)
		move.l	(a7)+,a2
		subq.l	#1,CloseLock
		rts

	endc

OnOff
		dc.b	1,0
MungeVal
		dc.l	$01010101
OldFreeMem	
		dc.l	0
CloseLock
		dc.l	0

	ifnd	MUNGELAYER
	ifnd	PATCHED
OldCloseWindow
		dc.l	0
IntuiBase
		dc.l	0
IntuiName
		dc.b	'intuition.library',0
		ds.w	0
	endc
	else
OldDeleteLayer
		dc.l	0
LayersBase
		dc.l	0
LayersName
		dc.b	'layers.library',0
		ds.w	0
	endc

MungeName
		dc.b	'munge.port',0
		ds.w	0
MungePort
		dc.l	0,0			; Pred,Succ
		dc.b	NT_MSGPORT	; Type
		dc.b	0			; Pri
		dc.l	MungeName	; Name
		dc.b	PA_IGNORE	; Flags = Ignore
		dc.b	0			; No Signal #
		dc.l	0			; Place for task pointer
		ds.b	LH_SIZE		; List (not initialized)
MungeState
		dc.w	0			; munge state