The Bootsect section has been completed and the program jumps to the Setup section:
start:! OK, the read went well so we get current cursor position and save it for! posterity. mov Ax, #INITSEG ! This is do in bootsect already ... mov Ds,ax mov Ah, #0x03 ! Read cursor Pos xor bh,bh int 0x10 ! Save it in known place, Con_init fetches mov [0],dx ! it from 0x90000.
First read the location of the cursor, and then stored in the memory 0x90000 address, from the front, the bootsect part of the code is stored in memory address 0x90000, but now there is no use of this memory to save some parameters (and did not open up new memory space, Reuse this segment of memory space).
! Get Memory Size (extended mem, KB)movah, #0x88int0x15mov[2],ax
Then call the int 15h interrupt routine to get the memory size, in kilobytes.
! Get video-card data:movah, #0x0fint0x10mov[4],bx! BH = Display pagemov[6],ax! Al = video mode, ah = window width
Read the video card data.
! Check for EGA/VGA and some config parametersmovah, #0x12movbl, #0x10int 0x10mov[8],axmov[10],bxmov[12],cx
Check the display mode and get configuration parameters.
! Get hd0 datamovax, #0x0000movds,axldssi,[4*0x41] movax, #INITSEGmoves,axmovdi, #0x0080mov CX, #0x10repMOVSB
Copy the first hard drive parameter table to memory 0x90080 address, size 16 bytes, stored at 0x90080 address.
! Get HD1 datamovax, #0x0000movds,axldssi,[4*0x46] movax, #INITSEGmoves,axmovdi, #0x0090mov CX, #0x10repMOVSB
Copy the second hard drive parameter table to the memory 0x90090 address, size 16 bytes, stored at the 0x90090 address.
! Check that there is a hd1:-)movAX, #0x01500movDL, #0x81Int0x13JcNo_disk1CmpAh, #3JeIs_disk1no_disk1:movAX, #INITSEGmovEs,axmovDI, #0x0090movCX, #0x10movAX, #0x00RepStosbis_disk1:
Check for the presence of a second hard disk (HD1) and, if it does not exist, zero the hard disk parameter table at the 0x90090 address.
! Now we want-to-move to protected mode ... CLI! No interrupts allowed!
will be working in protected mode, the first is to shut down the interrupt.
! First we move the system to it's rightful placemovAX, #0x0000Cld! ' Direction ' =0, Movs moves forwarddo_move:movEs,ax! Destination segmentAddAX, #0x1000CmpAX, #0x9000JzEnd_movemovDs,ax! Source SegmentSubDi,diSubSi,simovCX, #0x8000RepMovswjmpDo_move
The system section is then moved from the memory 0x10000 address to the memory 0x00000 where the size of the move is 0x80000, which is the 512kB size (that is, the system portion cannot exceed 512kB).
! Then we load the segment Descriptorsend_move:movax, #SETUPSEG! Right, forgot. Didn ' t work:-)movds,axlidtidt_48! Load IDT with 0,0lgdtgdt_48! Load GDT with whatever appropriate
Used to load Global descriptor (GDT) tables and Interrupt descriptor Table (IDT).
! That is painless, now we enable A20 call empty_8042mov al, #0xD1! Command Writeout #0x64, alcall empty_8042mov al, #0xDF! A20 on Off #0x60, Alcall empty_8042
The empty_8042 child function is used to test whether the 8042 controller input buffer is empty, and only if it is empty can the write command be performed.
! This routine checks, the keyboard command queue is empty! No Timeout is used-if the hangs there is something wrong with! The machine, and we probably couldn ' t proceed anyway.empty_8042:. Word 0x00eb,0x00ebin Al, #0x64 ! 8042 status PortTest al, #2! is input buffer full? jnz empty_8042! Yes-loopret
So the front is used to enable A20 address bus, and the addressing space is changed from 1MB to 4GB.
! Well, that went OK, I hope. Now we had to reprogram the interrupts:-(! We put them right after the intel-reserved hardware interrupts, at! int 0x20-0x2f. There they won ' t mess up anything. Sadly IBM really! Messed this and the original PC, and they haven ' t been able to! Rectify it afterwards. Thus the BIOS puts interrupts at 0x08-0x0f,! Which is used for the internal hardware interrupts as well. We just! Has to reprogram the 8259 ' s, and it isn ' t fun. mov AL, #0x11 ! Initialization sequence out #0x20, Al &N Bsp ! Send it to 8259a-1 . Word 0X00EB,0X00EB ! JMP $+2, jmp $+2 out #0xA0, Al &N bsp;! and to 8259a-2 . Word &nbsP 0x00eb,0x00eb mov AL, #0x20 &NBSP ;! Start of hardware int ' s (0x20) out #0x21,al . Word &nbs P 0x00eb,0x00eb mov AL, #0x28 &NBSP ;! Start of hardware int ' s 2 (0x28) out #0xA1,al . Word &n Bsp 0x00eb,0x00eb mov AL, #0x04 &NBSP ;! 8259-1 is master out #0x21,al . Word 0x00eb,0x00 eb mov AL, #0x02 ! 8259-2 is slave out #0xA1,al . Word 0x00eb,0x00e b &nbsP mov AL, #0x01 ! 8086 mode for both out #0x21,al . Word 0x00eb,0x 00eb out #0xA1,al . Word 0x00eb,0x00eb &NB Sp mov AL, #0xFF ! Mask off all interrupts to now out #0x21,al . Word &nb Sp 0x00eb,0x00eb out #0xA1, AL
The above code is used to initialize the 8259A interrupt controller.
! Well, that's certainly wasn ' t fun:-(. Hopefully it works, and we don ' t! Need no steenking BIOS anyway (except for the initial loading:-).! The bios-routine wants lots of unnecessary data, and it ' s less! "Interesting" anyway. This is what REAL programmers do it.!! Well, now's the time to actually move into protected mode. To make! Things as simple as possible, we do no register set-up or anything,! We let the gnu-compiled 32-bit programs does that. We just jump to! Absolute address 0x00000, in 32-bit protected mode. mov ax, #0x0001! Protected mode (PE) bitLMSW AX! This is it! Jmpi 0,8! JMP offset 0 of Segment 8 (CS)
Finally the real entry protection mode, jump to 0 address, that is, the system section.