try2.asm

; boot.asm
; bin version

[BITS 16]

; from the Programmer’s Reference Manual
;The segment containing the currently executing sequence of instructions is known as the current code segment;
;it is specified by means of the CS register. The 80386 fetches all instructions from this code segment, using
;as an offset the contents of the instruction pointer. CS is changed implicitly as the result of intersegment
;control-transfer instructions (for example, CALL and JMP), interrupts, and exceptions.
;The instruction pointer register (EIP) contains the offset address, relative to the start of the current code
;segment, of the next sequential instruction to be executed. The instruction pointer is not directly visible
;to the programmer; it is controlled implicitly by control-transfer instructions, interrupts, and exceptions.
;As Figure 2-9 shows, the low-order 16 bits of EIP is named IP and can be used by the processor as a unit.
;This feature is useful when executing instructions designed for the 8086 and 80286 processors.
; from http://www.supernovah.com/Tutorials/BootSector2.php
;As stated earlier, we cannot be sure if the BIOS set us up with the starting address of 0x7C0:0x0 or 0x0:0x7C00.
;We will use the second segment offset pair to execute our boot sector so we know for sure how the CPU will access
;our code. To do this, our very first instruction will be a far jump that simply jumps to the next instruction.
;The trick is, if we specify a segment, even if it is 0x0, the jmp will be a far jump and the CS register will be
;loaded with the value 0x0 and the IP register will be loaded with the address of the next instruction to be
;executed.
;[BITS 16]
;[ORG 0x7C00]
;jmp 0x0:Start
;Start:
; This code will set the CS segment to 0x0, set the IP register to the the very next instruction which will be slightly past 0x7C00, ….

; universal-loop
;     {
;       start-ORG-nguye^n-thu?y: maintain-gi`n-giu+~ba?o-to^`n (“muo^n loa`i ddu+o+.c so^’ng la^u bi`nh thu+o+`ng; everyone live long and well”); // in “gia ba?o”, “ba?o” ~ maintain as in “ba?o thu?/to^`n” …
; try/if   ;// tin messages …. the try/if is the “gia” of “gia ba?o” …
;  maintain-gi`n-giu+~-ba?o-to^`n (“muo^n loa`i va` messageA va` messageB va` messageNEW va` tinLA`NH va`… ddu+o+.c so^’ng la^u bi`nh thu+o+`ng; everyone live long and well”); // the message “stack” is loaded or push-pop with messages …; // push-and-pop-or-sent-and-receive (&messageNEW-hay-tinLA`NH); // tin and shakespeare’s version of “all roads lead to rome”: “doubt thou the stars are fire doubt truth to be a liar but never doubt I loved ‘muo^n loa`i ddu+o+.c so^’ng la^u bi`nh thu+o+`ng; everyone live long and well'”:  1/19/2014 Sunday Service … Gospel ~ Good News Tin La\nh …”Gia Ba?o”:  the “gia” attempts to reach an agreement with the “ba?o” …// salinger on internet news: push/pop/create stack/heap by an expansion assignment (“muo^n loa`i” <= “muo^n loa`i va` messageA va` messageB va` messageC va` ….”)
; ;catch/else  ;// unmaintainable tin/messages or kho’ tin hay kho^ng tin no messages … SBTN Uye^n Thi. commercial for MBR [master boot record] “kho’ tin nhu+ng co’ tha^.t …”
; ; go-to-jump-tro+?-ve^` start-ORG-nguye^n-thu?y: maintain-gi`n-giu+~-ba?o-to^`n (“muo^n loa`i ddu+o+.c so^’ng la^u bi`nh thu+o+`ng; everyone live long and well”);
; go-to-jump-tro+?-ve^` start-ORG-nguye^n-thu?y: maintain-gi`n-giu+~-ba?o-to^`n (“muo^n loa`i ddu+o+.c so^’ng la^u bi`nh thu+o+`ng; everyone live long and well”);
;     }

; from http://wiki.osdev.org/Babystep2:
;some say that the bootloader is is loaded at 0000:7C00, while others say 07C0:0000.
;This is in fact the same address: 16 * 0x0000 + 0x7C00 = 16 * 0x07C0 + 0x0000 = 0x7C00.
%define MEMORYSEGMENTREALLOWBOUND 0x7C00
%define SEGMENTSIZE   512
%define MEMORYSEGMENTREALUPPERBOUND MEMORYSEGMENTREALLOWBOUND + MEMORYSEGMENTREALUPPERBOUND

%define ORIGIN 1
%ifdef ORIGIN
[ORG 0x7c00]
; segment:offset … ds:offset or cs:offset … 0:offset-from-0x7COO … that is, labels in code following is addressed as 0:0x7C00+offset-from-start-of-file

;Following code will set the CS segment to 0x0, set the IP register to the the very next instruction which will be slightly past 0x7C00, ….
jmp 0x0:start  ; set up the ip stack pointer and cs segment register implicitly via jmp instruction
; jmp start  ; set up the ip stack pointer and cs segment register implicitly via jmp instruction

%else
[ORG 0]
; segment:offset … ds:offset or cs:offset …  0x07C0:offset-from-0 … that is, labels in the code following is addressed as 0x07C0:0+offset-from-start-of-file

;Following code will set the CS segment to 0x07C0, set the IP register to the the very next instruction which will be slightly past 0x0, ….
jmp 0x07C0:start ; set up the ip stack pointer and cs segment register implicitly via jmp instruction
; jmp start  ; set up the ip stack pointer and cs segment register implicitly via jmp instruction

%endif

; data segment
datasegment   dw      123

; stack segment
stacksegment  resb 64
stacktop:

; set up the data, stack, etc. segment registers
start:
;mov    ax,seg DATASEGMENT1
;mov ax, 0x0
mov ax, datasegment
mov     ds,ax
;mov    ax,seg STACKSEGMENT
mov ax, stacksegment
mov     ss,ax
mov     sp,stacktop

; from http://wiki.osdev.org/Babystep2:
; In real mode, addresses are calculated as segment * 16 + offset. Since offset can be much larger than 16, there are many pairs
; of segment and offset that point to the same address.
%define REALADDRESS(SEGMENTNO,OFFSETNO) SEGMENTNO*16+OFFSETNO

%define VERIFYSEGMENTADDRESSBOUND(SEGMENTADDRESSTOVERIFY, OFFSETADDRESSTOVERIFY) \
(REALADDRESS(SEGMENTADDRESSTOVERIFY,OFFSETADDRESSTOVERIFY) > MEMORYSEGMENTREALLOWBOUND) \
& (REALADDRESS(SEGMENTADDRESSTOVERIFY,OFFSETADDRESSTOVERIFY) < MEMORYSEGMENTREALUPPERBOUND)
; generate some virtual segment:offset address for use with a real address …
; %define GENERATESEGMENTADDRESS(REALADDRESSNO, &GENSEGMENTNO, &GENOFFSETNO) …………….
; %define GENERATEVIRTUALSEGMENTADDRESS(REALADDRESSNO, VIRTUALOFFSETADDRESSINPUT) (REALADDRESSNO – VIRTUALOFFSETADDRESSINPUT)/16
; %define GENERATEOFFSETNO(REALADDRESSNO, VIRTUALSEGMENTADDRESSINPUT) (REALADDRESSNO – VIRTUALSEGMENTADDRESSINPUT * 16)

; from http://geezer.osdevbrasil.net/johnfine/segments.htm:
;The way it really works
; Each segment register is really four registers: •A selector register
;•A base register
;•A limit register
;•An attribute register
;
;In all modes, every access to memory that uses a segment register uses the base, limit, and attribute portions of the segment register and does not use the selector portion.
;Every direct access to a segment register (PUSHing it on the stack, MOVing it to a general register etc.) uses only the selector portion. The base, limit, and attribute portions are either very hard or impossible to read (depending on CPU type). They are often called the “hidden” part of the segment register because they are so hard to read.
;Intel documentation refers to the hidden part of the segment register as a “descriptor cache”. This name obscures the actual behavior of the “hidden” part.
; In real mode (or V86 mode), when you write any 16-bit value to a segment register, the value you write goes into the selector and 16 times that value goes into the base. The limit and attribute are not changed.
;In pmode, any write to a segment register causes a descriptor to be fetched from the GDT or LDT and unpacked into the base, limit and attribute portion of the segment register. (Special exception for the NULL Selector).
;When the CPU switchs between real mode and pmode, the segment registers do not automatically change. The selectors still contain the exact bit pattern that was loaded into them in the previous mode. The hidden parts still contain the values they contained before, so the segment registers can still be used to access whatever segments they refered to before the switch.

;Writes to a segment register
;When I refer to “writing to a segment register”, I mean any action that puts a 16-bit value into a segment register.
;The obvious example is something like:
;  MOV  DS,AX
;However the same rules apply to many other situations, including: •POP to a segment register.
;•FAR JMP or CALL puts a value in CS.
;•IRET or FAR RET puts a value in CS.
;•Both hardware and software interrupts put a value in CS.
;•A ring transition puts a value in both SS and CS.
;•A task switch loads all the segment registers from a TSS.

; from the Programmer’s Reference Manual
;The segment containing the currently executing sequence of instructions is known as the current code segment;
;it is specified by means of the CS register. The 80386 fetches all instructions from this code segment, using
;as an offset the contents of the instruction pointer. CS is changed implicitly as the result of intersegment
;control-transfer instructions (for example, CALL and JMP), interrupts, and exceptions.

; from http://www.supernovah.com/Tutorials/BootSector4.php:
;Video Memory
;As previously stated, what is printed to the screen is simply controlled by a special section of memory called
;the video memory (or VGA memory). This section of memory is then periodically copied to the video device
;memory which is then presented to the screen by the Digital Analog Converter (DAC). Currently we are in text
;mode 03h which is a form of EGA. The video memory for text mode 3h begins at 0xB8000. Text mode 03h is 80 characters wide
;and 25 characters tall. This gives us 2000 total characters (80 * 25). Each character consists of 2 bytes which
;yields 4000 bytes of memory in total. So this means that text mode 03h stores it’s video information (the information that is
;printed to the screen) at the memory address 0xB8000 and it takes up 4000 bytes of memory.
;Printing Character to the Screen
;The first we must do in order to print character to the screen is to get a segment register setup that points
;to the memory location 0xB8000 [= 753664 = 47104 * 16]. Remember that segments in real mode have the lower four bits implicitly
;set to zero and because each hex digit represents four bits we can easily drop the right most zero on the
;memory address when storing it in a segment register. We will use the ES segment register because we
;still want to access our data with the DS segment so we don’t run into problems when using instructions that
;implicitly use the DS segment by default.
;mov AX,0xB800 ;// = 47104
;mov ES,AX

;screen output …
;for the screen, the messages in (“muo^n loa`i” <= “muo^n loa`i va` messageA va` messageB va` messageC va` ….”) are pixels …
;(“muo^n loa`i va` pixel1 va` pixel2 va` … ddu+o+.c so^’ng la^u bi`nh thu+o+`ng; everyone live long and well”)
screen:
.setupvideosegment:
mov AX,0xB800 ;// = 47104
mov ES,AX

;Clearing the Background
;Clearing the background is rather trivial. The goal is to set all of the attribute bytes to the background color
;you wish to clear it to. The basic idea is to create a loop that will set every other byte, starting at the first
;attribute byte, to the background color we wish to clear to. We must also be sure to only clear all of the attributes that
;are used to represent the string. In other words, be sure not to go past the last attribute byte. The last attribute byte is
;found at 80 * 25 * 2 – 1. The 80 is the width and the 25 is the height. The 2 is there because two bytes make up each
;character; one for the character and one for the attribute. Finally the 1 is subtracted because our first attribute byte is
;actually the second byte at the beginning The 1 simply takes into account that we start our count at one instead of zero.

.clearscreenpixels:
mov CX,80 * 25 * 2 – 1
mov BX,1
Loopthroughscreenpixels:
cmp BX,CX
ja finishclearscreenpixels
mov byte [ES:BX],10h ;Set background to blue
;and the text to black
;with no flashing text
add BX,2
jmp Loopthroughscreenpixels
finishclearscreenpixels:
;jmp exit

.sayhello:
mov byte [ES:0],’H’
mov byte [ES:2],’o’
mov byte [ES:4],’p’
mov byte [ES:6],’e’
mov byte [ES:8],’ ‘
mov byte [ES:10],’W’
mov byte [ES:12],’e’
mov byte [ES:14],’l’
mov byte [ES:16],’l’
;jmp exit
exit:

hang:
jmp hang ; or, equivalently in nasm: jmp $

times 510-($-$$) db 0 ; 2 bytes less now; $ = beginning of current line/expression = “times”, $$ = beginning of current section = “hang:”
db 0x55
db 0xAA

Leave a comment