I've written a small piece of code in x86 assembly language that runs on bare hardware which, at this point, goes as far as enabling protected 32-bit mode
I've run into a problem, however, pertaining printing to the screen. I've read that to do so without interrupts one may load characters into a special memory region, namely RAM address 0xb8000.
Knowing this, I wrote a function that does exactly that, and it proved a success when tested in qemu. However, and here comes the problem, when I attempt to run this program on a real machine (namely a Lenovo G470 laptop) it fails to display the string I want shown by writing to the display memory region. All other strings displayed using BIOS interrupts work as intended, alas, the 32-bit printing function does not seem to do anything. The program doesn't crash though, and a blinking cursor appears after the lines printed using interrupts.
If it's of any importance, I'm trying to boot this off a USB drive
Put much more bluntly, string S3 isn't printing in my laptop, it is in qemu and I've no idea why.
Here is my code, I apologize in advance for the lack of finesse:
[BITS 16] ;NASM 16-BIT MODE
[ORG 0x7C00] ;OFFSET MEMORY LOCATIONS TO BSECTOR/ BIOS LOADS MBR INTO THIS ADDRESS.
XOR AX, AX ;INITIALIZE SEGMENT REGISTERS BY AX
MOV DS, AX ;INDIRECTLY INITIALIZING DS REGISTER
MOV ES, AX ;INDIRECTLY INITIALIZING ES REGISTER
MOV GS, AX ;INDIRECTLY SETTING GS REGISTER
MOV FS, AX ;INDIRECTLY SETTING DS REGISTER
MOV SP, 0X900 ;SETTING STACK POINTER TO 0X900, OFFSET FROM 0X0 = 0X7C00
MOV BP, SP ;
JMP WORD 0x0:START16 ;JUMP TO START OF PROGRAM
PSR16B: ;16-BIT PRINT ROUTINE
MOV SI, BX ;ASSIGN SI POSITION OF STRING
MOV AH, 0XE ;TTY MODE
PSR16BLOP0: ;PRINT LOOP
LODSB ;LOAD SI INTO AL AND +1 ADDRESS OF STRING
CMP AL, 0X0 ;CONDITIONAL
JE PSR16LOP0END ;END LOOP
INT 0X10 ;BIOS INTERRUPT, PRINT AL TO SCREEN
JMP PSR16BLOP0 ;LOOP TO LOP
PSR16LOP0END: ;END OF LOOPA
MOV AL, 0XA ;NEW LINE ASCII
INT 0X10 ;RAISING PRINT BIOS INTERRUPT
MOV AL, 0XD ;NEWLINE 'CHARACTER' ASCII
INT 0X10 ;RAISING PRINT BIOS INTERRUPT
ADD CH, 0X1 ;ADD ONE TO COUNTER
RET ;RETURN TO LAST ADRESS BEFORE CALL
PSR16BEND: ;END OF FUNCTION, UNUSED
S0: ;STRING
DB 'BOOTING SEQUENCE INITIALIZED',0
S1: ;STRING
DB 'LOADING GDT',0
S2: ;STRING
DB 'ENTERING 32-BIT PROTECTED MODE',0
GDTS: ;START OF GLOBAL DESCRIPTOS TABLE
GDTN: ;NULL BEGGINING, 8 BYTES
DQ 0X0
GDTC: ;TABLE FOR CODE SEGMENT
DW 0XFFFF ;BITS 0-15 OF LIMIT(MAXADRESSUNIT) ||0X0-0XF
DW 0X0 ;BASE(SEGMENTSTART), BITS 0-15 ||0XF-0X1F
DB 0X0 ;BASE, BITS 16-23 ||0X20-0X27
DB 10011010B ;ACCESS BYTE ||0X28-0X2F
DB 11001111B ;SECOND4BITS:LIMITBITS 16-19/FIRST4BITS:FLAGS= ||0X30-0X37
DB 0X0 ;BASE, BITS 24-31||0X38-0X3F
GDTD: ;TABLE FOR DATA SEGMENT
DW 0XFFFF ;BITS 0-15 OF LIMIT(MAXADRESSUNIT) ||0X0-0XF
DW 0X0 ;BASE(SEGMENTSTART), BITS 0-15 ||0XF-0X1F
DB 0X0 ;BASE, BITS 16-23 ||0X20-0X27
DB 10010010B ;ACCESS BYTE ||0X28-0X2F
DB 11001111B ;SECOND4BITS:LIMITBITS 16-19/FIRST4BITS:FLAGS= ||0X30-0X37
DB 0X0 ;BASE, BITS 24-31||0X38-0X3F
GDTE: ;END OF GLOBAL DESCRIPTION TABLE
GDTDESC: ;GDT DESCRIPTOR
DW GDTE - GDTS - 1 ;SIZE OF GDT, 2 BYTE, MUST BE LESS THAN 1
DD GDTS ;ADRESS OF GDT, 4 BYTE
GDTDESCEND: ;END OF GDTDESC, UNUSED
CODESEG EQU GDTC - GDTS ;CODE SEGMENT ADDRESS CONSTANT
DATASEG EQU GDTD - GDTS ;DATA SEGMENT ADDRESS CONSTANT
START16: ;START OF BOOTSECTOR PROGRAM
MOV CH, 0X0 ;LINES COUNTER.
MOV BX, S0 ;SET STRING POINTER
CALL PSR16B ;CALL PRINT FUNCTION
MOV BX, S1 ;SET STRING POINTER
CALL PSR16B ;CALL PRINT FUNCTION
LGDT [GDTDESC] ;LOADING GDT DESCRIPTOR
MOV BX, S2 ;SET STRING POINTER
CALL PSR16B ;CALL PRINT FUNCTION
CLI ;SEVERING INTERRUPTS
MOV EAX, CR0 ;INDIRECTLY SETTING PROTECTED MODE BIT
OR EAX, 0X1 ;SETTING PMODE BIT
MOV CR0, EAX ;PROTECTED MODE ENABLED
JMP CODESEG:START32 ;FAR JUMP TO 32 BIT LAND
[BITS 32] ;NASM 32-BIT MODE
S3: ;STRING
DB '32-BIT PROTECTED MODE ENABLED', 0
PSR32B: ;PRINT TO DISPLAY ROUTINE FOR 32-BIT PREOTECTED MODE
PSR32BLOP0: ;INITIALIZE VGA REGION POINTER
CMP CL, 0X0 ;CONDITIONAL, IF FALSE SKIP INITIALIZATION
JNE PSR32BLOP0END ;END LOOP
MOV EBX, 0XB8000 ;INITIALIZING POINTER TO VGA MEMORY REGION
ADD CL, 0X1 ;ADD TO COUNTER
JMP PSR32BLOP0 ;LOOP
PSR32BLOP0END: ;END OF FUNCTION
PSR32BLOP1: ;USED TO INTIALIZE VGA MEMORY POINTER, NEWLINE OFFSET FROM 16-BIT LINES
CMP CH, 0X0 ;END CONDITIONAL
JE PSR32BLOP1END; ;JUMP TO END OF LOOP
ADD EBX, 0XA0 ;ADD EQUIVALENT OF ONE LINE TO POINTER
SUB CH, 0X1 ;LOOP END COUNTER
JMP PSR32BLOP1 ;LOOP
PSR32BLOP1END: ;USED TO INTIALIZE VGA MEMORY POINTER, END
MOV ESI, EDX ;LOAD LODSW STRING POINTER WITH APPROPIATE ADDRESS
MOV AH, 0X0F ;BLACK BACKGROUND, WHITE LETTERS
PSR32BLOP2: ;PRNTINH LOOP
LODSB ;LOAD CHARACTER INTO AL
CMP AL, 0X0 ;CHECK FOR END OF STRING
JE PSR32BLOP2END ;IF AX IS 0 JUMP TO END OF LOOP
MOV [EBX], AX ;LOAD WORD CHARACTER INTO VGA MEMORY
ADD EBX, 0X2 ;MOVE TO NEXT CHARACTER WORD IN MEMORY ADDRESS
JMP PSR32BLOP2 ;LOOP BACK TO START
PSR32BLOP2END: ;END OF LOOP
RET
ENDPSR32B: ;END OF FUNCTION, UNUSED
START32: ;START OF 32 BIT PROTECTED PROGRAM
MOV AX, DATASEG ;SET DATA SEGMENT ADDRESS TO POINTER
MOV DS, AX ;INITIALIZING SEGMENT REGISTERS
MOV SS, AX ;INITIALIZING SEGMENT REGISTERS
MOV [ES:DI], DL ;INITIALIZING SEGMENT REGISTERS
MOV DS, AX ;INITIALIZING SEGMENT REGISTERS
MOV GS, AX ;INITIALIZING SEGMENT REGISTERS
MOV EDX, S3 ;STRING POINTER DX
CALL PSR32B ;CALL PRINT ROUTINE// THIS IS A TEST
JMP $ ;LOOP TO INFINITY
PAD: ;BOOTSECTOR PADDING & MAGIC NUMBER
TIMES 510-($-$$) DB 0 ;FILL 0S TO END OF SECTOR
DW 0xAA55 ;BOOT SIGNATURE
EDIT: Setting CL to 0 at start32: fixed the problem