Asserting CPUID and enabling A20
These observations are for the most in the order of the code


  At this point, the user will probably want to know if this system is Long Mode capable, which is indicated by the word CPUID in green. This is determined by attempting to toggle bit 21 in EFLAGS.


Seeing "This is determined by..." makes this paragraph somewhat mis-leading because it would seem that Long Mode capability is determined merely by looking at EFLAGS[21]. Your code correctly does it in a 3-step process, but that's not something that the reader sees right away. People with less time on their hands might have given up reading already!


push     bp  
mov      bp, sp  
...
or       [bp-6], 20H 
...
pop      bp



You've used the BP register to set a bit in a stacked number. This can be optimized by writing or [esp+2], 20H. Although this instruction requires 2 extra bytes (ASP prefix and SIB byte), you gain 4 bytes from dropping the push, mov, and pop instructions.
There's a trade off here. If in a similar situation, you were to manipulate several stacked values in a row then using BP would be shorter.


bt       ax, 5           Is bit 21 on    
jnc      603             No if CY=0



Bit 5 lives in the AL register. Testing to see if it is on or off can be shortened by not using the double opcode instruction BT. Best choice here is the Modr/m byte less instruction test al, imm8.

test    al, 20h
jz      603          ;Bit 21 is off



5DF  66B801000080      mov      eax, 0x80000000 Ext Func supported? 



Noticed the discrepancy between the dump and the instruction's immediate?
If you copy/pasted this code then there's something amiss with the disassembler, else it's a typo.


push     eax 
cpuid    
pop      ecx 
cmp      eax, ecx            
jna      603         AX &gt;= 80000001H
mov      [bp], YELLOW    
mov      al, 1       AX = Read feature bits  
cpuid    
bt       edx, 29     Long Mode?  
jnc      603



With the instruction mov al, 1 you're avoiding to have to write the much longer mov eax, 80000001H. Very understandable but the 1 byte inc ax would still be shorter.
There's also some danger lurking in this code snippet. Who is to say that Intel/AMD in future iterations of the processor will not be returning non-zero values in EAX[8,31] ? Already today some leaf numbers aren't used.

push    eax           ;(1)
cpuid
xchg    ecx, eax      ;Result from CPUID
pop     eax           ;(1)
cmp     ecx, eax
jna     603
mov     [bp], YELLOW
inc     ax
cpuid
bt      edx, 29     Long Mode?  
jnc     603


By popping exactly 80000000h, you guarantee that the inc ax will produce the desired 80000001h.
I've used xchg ecx, eax because it's 1 byte shorter than mov ecx, eax.


mov      bx, cx  
mov      bl, [bp]        Selected color  



Since the first instruction just wants to zero the BH register, you could shave off 1 byte by writing:

movzx    bx, [bp]        Selected color  



push      di
push      si
lodsw    
neg       ax 
stosw    
cmp       [si-2], ax   If equal A20 is off
pop       si 
pop       di



When I first saw this use of string primitives I expected to see a range of addresses to be compared, but you only process a single word. Next code then uses less instructions and is a few bytes shorter. Note the use of the Segment Override Prefix.

mov     ax, [si]
neg     ax
mov     [es:di], ax
cmp     [si], ax


Using the previous code you can also stop using DI and shave off another 4 bytes since you know that DI=SI+16:

mov     ax, [si]
neg     ax
mov     [es:si+16], ax
cmp     [si], ax


One final point about this code is about the use of neg. The negation of zero is also zero. That's why this kind of testing often uses not which guarantees the value gets modified.  This doesn't impact your code however since you've chosen an address that certainly does not contain zero. But choosing a fixed address like eg. 21h*4 (DOS isn't loaded for sure) would make setting up SI much shorter and even allow you to not use SI at all.

mov     ax, [0084h]
not     ax
mov     [es:0084h+16], ax
cmp     [0084h], ax



61F  81C66000          add       si, 60H       Offset from CS   



I don't know what happened here, but I think the compiler ought to give you the sign-extended version of this instruction automatically. Bytes 83h,C6h,60h.


648  49                dec       cx 
649  75E4              jnz       62f        Execute test again



This of course is just loop. 1 byte shorter.

My last concern


6D4  B21C              mov       dl, 0x1c



You didn't initialize the DH register because you know it has the correct value from the code above. That's fine but given the separation between setting it up and using it, and considering the note you've included, ...


  NOTE: There is 125 bytes reserved here for additional methods of enabling A20.


... I wonder if you will remember to preserve DH the day you're ready to add these additional methods?