boothead.s
Skip to line: 3100 - 3200 - 3300 - 3400 - 3500 - 3600 - 3700 - 3800 - 3900 - 4000 - 4100 - 4200 - 4284


Highlighted entries were made in the last day
Select a different time increment to highlight entries
Current GMT time: Mar 10 2010 13:58:12

If you have a comment for boothead.s, please click here.
Name: GoploieEmail:  m1s7@yandex.ruDate: Oct 27 2009 23:01:57 GMT
Subject:  line+3074
Reponse: http://khwsusobql.jimdo.com хотелось бы? вдуть той самой в попку? http://vfcolplwwp.jimdo.com
 
Respond to Goploie's comment.
 
 
Name: rcmicbznuEmail:  msirjq@exohpq.comDate: Oct 03 2009 11:50:43 GMT
Subject:  tlyPnLmGJCYsPILqqGx
Reponse: c8zBEX gkawfhyqpfwh, [url=http://meiqycpvrxjq.com/]meiqycpvrxjq[/url], [link=http://zdyzgriynmqe.com/]zdyzgriynmqe[/link], http://dsywvfpmuxfp.com/
 
Respond to rcmicbznu's comment.
 
 
Name: JohnEmail:  john@mail.comDate: Sep 27 2009 03:10:58 GMT
Subject:  serfer
Reponse: hi, good site. 111 [URL=http://www.link222.com]222[/URL] http://www.link333.com
 
Respond to John's comment.
 
 
Name: jamesEmail:  jameswang98@gmail.comDate: Dec 29 2008 03:32:48 GMT
Subject:  ask for more background/explanation for _relocatio
Reponse: It's really difficult to understand function _relocate:
3346 .define _relocate
3347 _relocate:
Would anybody here please give more explanation to help understanding ? /happy Xmas , Many thanks
 
Respond to james's comment.
 
 
Name: Christos KarayiannisEmail:  christos@kar.forthnet.grDate: Dec 05 2005 17:56:24 GMT
Subject:  line 3074
Reponse: At the comment of line 3074 there is a question about the "! Round down to even " code comment. The specific memory area should be an even one because the stack pointer is placed there. The sp certainly is better to be aligned at an even number in the address space, because at the stack are usually pushed 16-bit register values, variables of word size etc
 
Respond to Christos Karayiannis's comment.
 
 
3000   !       Boothead.s - BIOS support for boot.c            Author: Kees J. Bot
3001   !
3002   !
3003   ! This file contains the startup and low level support for the secondary
3004   ! boot program.  It contains functions for disk, tty and keyboard I/O,
3005   ! copying memory to arbitrary locations, etc.
3006   !
Expand/Collapse Item3007    ! The primary bootstrap code supplies the following parameters in registers:
These are the same values that were passed into bootblock.s.
3008   !       dl      = Boot-device.
3009   !       es:si   = Partition table entry if hard disk.
3010   !
3011
3012   .define begtext, begdata, begbss
3013   .data
3014   begdata:
3015           .ascii  "(null)\0"      ! Just in case someone follows a null pointer
3016   .bss
3017 begbss:
3018
Expand/Collapse Item3019            o32         =     0x66  ! This assembler doesn't know 386 extensions
In Makefile, boothead.s is compiled with the -mi86 option (LD86 contains the mi86 option).  This option uses the machine instructions (mi) of the 8086 system which does not have 32-bit registers (like eax, ebx, etc.).  If an instruction is needed that uses a 32-bit value, the 8086 instruction must be prefixed with 0x66.

Look at line 3933.  If the -mi86 option is used and the retf instruction has no prefix, the instruction jumps to the address specified by the last 2 bytes on the stack (the offset) and the next-to-last 2 bytes on the stack (the segment).  However, if the last 4 bytes on the stack are the offset and the next-to-last 4 bytes on the stack are the segment and the -mi86 option is used, the instruction must be prefixed with 0x66.  On lines 3922-3925, these 8 bytes are pushed on the stack.

Expand/Collapse Item3020            BOOTOFF     =   0x7C00  ! 0x0000:BOOTOFF load a bootstrap here
Expand/Collapse Item3021            LOADSEG     =   0x1000  ! Where this code is loaded.
Expand/Collapse Item3022            BUFFER      =   0x0600  ! First free memory
The bootstrap (which is bootblock.s) loaded this code (the secondary boot loader) at address 0x1000:0x0000.  If the user wishes to boot a different partition, the bootstrap from that partition is loaded at address 0x0000:0x7C00 and the boot process repeats itself (the bootstrap loads the secondary boot loader which loads the kernel). masterboot.s and bootblock.s describe this process in greater detail.
Expand/Collapse Item3023            PENTRYSIZE  =       16  ! Partition table entry size.
Expand/Collapse Item3024            a_flags     =        2  ! From a.out.h, struct exec
In your book, look at line 01400.  This is the header file a.out.h.  The first thing declared in this file is the struct exec.  All minix executables (with a few exceptions like bootblock and masterboot - these 2 files must begin with executable code) begin with headers.

a_flags is at an offset of 2 bytes, a_text is at an offset of 8 bytes, and so on.  a_flags describes the kernel (with the options shown on lines 3029-3033) and a_text, a_data, a_bss, and a_total are sizes.

Note that the A_SEP flag describes this executable (the secondary boot loader) whereas the K_I386, K_RET, K_INT86, and K_MEML flags describe the kernel.

3025           a_text      =        8
3026           a_data      =       12
3027           a_bss       =       16
3028           a_total     =       24
Expand/Collapse Item3029            A_SEP       =     0x20  ! Separate I&D flag
Read section 4.7.1 and the first 10 paragraphs of section 4.7.3 of Operating Systems and try to understand as much as you can.  Some of the terminology may be unfamiliar so I will give a short description of the concepts involved.

This executable (the secondary boot) is compiled with the -mi86 option and runs in real mode and not in protected mode.  For this reason, the secondary boot is not be able to take advantage of the protection features of protected mode.  However, since this is the first time we've run into the A_SEP flag, it's a good place to discuss shared vs. separate segments.

In protected mode, the text (code) and the data+bss+heap+stack (I will refer to this as the total data - see the next paragraph for a description of each of these) in an executable with separate text and total data segments are protected from one another.  For example, if the code tries to jump to a memory address that's within the total data segment, the hardware triggers a segment violation.  If they're not separate (A_SEP in a_flags is not set), chaos results.  Another advantage of separating the text and total data is that the text can be shared among multiple instances of the same program.  The total data will differ between two instances of the same program but the text will be the same.

Data contains initialized global variables, bss contains uninitialized global variables and must be initialized to zero (see lines 3091-1098), and the heap is the memory that malloc() allocates at run-time.

It's best to also keep the data+bss+heap and the stack separate - although Minix doesn't separate the two for the reasons given in section 4.7.3.  This means that if the heap or the stack grows too large, one can overwrite the other.  If the stack overwrites the heap and the overwritten data is not accessed immediately, identifying the problem is difficult.

On disk, the a_text field in the header holds the size of the text and the a_data field holds the size of the data.  If the kernel doesn't have separate text and total data segments, the variables a_data and a_text are combined into a_data and the variable a_text is set to zero (see lines 3069-3071).  Note that even though the values are changed in memory, they do not affect the values on disk. a_bss is the size of the bss.  a_total is the size of the data+bss+heap+stack (separate) or the text+data+bss+heap+stack (shared).  Unlike a_text, it doesn't need to be modified if the text and total data are shared. a_total determines the top of the stack (see lines 3075-3077) and is also used (with a_text) to determine the global variable _runsize (see lines 3127-3135) which is needed by boot.c in initialize().

Expand/Collapse Item3030            K_I386      =   0x0001  ! Call Minix in 386 mode
If the K_I386 flag is set for the kernel, this code must switch to protected mode.
Expand/Collapse Item3031            K_RET       =   0x0020  ! Returns to the monitor on reboot
Look at lines 3936 and 3942.  The minix kernel returns there on a halt or reboot if the K_RET is set for the kernel.  If the K_RET flag is not set, the system simply halts.

3032           K_INT86     =   0x0040  ! Requires generic INT support

Expand/Collapse Item3033            K_MEML      =   0x0080  ! Pass a list of free memory
The variable _mem (see line 3048) is used to pass this memory list.  The int 0x12 (see line 3141) and int 0x15 (see lines 3152 and 3157) bios calls are used to determine the low memory and high memory size.

3034

Expand/Collapse Item3035            DS_SELECTOR =      3*8  ! Kernel data selector
Expand/Collapse Item3036            ES_SELECTOR =      4*8  ! Flat 4 Gb
Expand/Collapse Item3037            SS_SELECTOR =      5*8  ! Monitor stack
Expand/Collapse Item3038            CS_SELECTOR =      6*8  ! Kernel code
Expand/Collapse Item3039            MCS_SELECTOR=      7*8  ! Monitor code
To support multiprocessing, the 80286 and up use global descriptor tables (GDT's).  p_gdt (line 4242) is the descriptor table.  Anything that is labeled UNSET must be filled in before the global descriptor table is loaded using the lgdt instruction (see line 4133).  These values are filled in on lines 3871-3897.

The following values are the offsets of the entries within the global descriptor table.  For example, since the entry for the kernel code is the 7th entry (see line 4267) and the size of each entry is 8 bytes, its offset is 6*8 (remember that the first entry has a 0 offset).  The MCS_SELECTOR is pushed onto the stack (if the K_RET flag is set for the kernel) before jumping to the kernel (look at lines 3918-3920) .  Also before the jump is made to the kernel, the ds and es registers are loaded with DS_SELECTOR and ES_SELECTOR, respectively.

3040

Expand/Collapse Item3041            ESC         =     0x1B  ! Escape character
0x1B is the ascii representation of ESC.

3042

Expand/Collapse Item3043    ! Imported variables and functions:
Memory for a variable can be allocated in only one file (i.e. the variable is "defined") but the variable must be declared as extern in every other file that accesses it.  To accomplish this, the macro EXTERN is #defined as the empty string in boot.c .  This prevents the EXTERN macro from being #defined as extern in boot.h when boot.h is #included in boot.c.  boot.h is also #included in bootimage.c.  Since EXTERN is not #defined (and is therefore undefined), EXTERN is replaced by extern in bootimage.c.  This mechanism ensures that memory for a variable is allocated only once.

A similar trick is used in the kernel.  Read the 5th paragraph of section 2.6.3 of Operating Systems for details.

Variables that are shared between assembler and C code are prefixed with an underscore ( _ ) in the assembler code but are not prefixed with an underscore in the C code.

Expand/Collapse Item3044    .extern _caddr, _daddr, _runsize, _edata, _end  ! Runtime environment
_caddr is the absolute address of the first byte of the text. _daddr is the absolute address of the first byte of the data. _runsize is the size of the entire executable (text+data+bss+heap+stack). I believe that _edata and _end are variables that are generated by the compiler. _edata is the offset address of the end of the data and _end is the offset address of the end of the bss.  These two variables are used on lines 3091-3098.  See the comment for line 3145 for further discussion of _edata and _end.
3045   .extern _device                                 ! BIOS device number
3046   .extern _rem_part                               ! To pass partition info
Expand/Collapse Item3047    .extern _k_flags                                ! Special kernel flags
_k_flags contains the K_I386 , K_RET, K_INT86, and K_MEML flags (lines 3030-3033).  _k_flags is set in bootimage.c.
3048   .extern _mem                                    ! Free memory list
3049
3050   .text
3051   begtext:
Expand/Collapse Item3052    .extern _boot, _printk                          ! Boot Minix, kernel printf
These functions are defined in boot.c. boot is called on line 3180.
3053
Expand/Collapse Item3054    ! Set segment registers and stack pointer using the programs own header!
Expand/Collapse Item3055    ! The header is either 32 bytes (short form) or 48 bytes (long form).  The
Expand/Collapse Item3056    ! bootblock will jump to address 0x10030 in both cases, calling one of the
Expand/Collapse Item3057    ! two jmpf instructions below.
3058
3059           jmpf    boot, LOADSEG+3 ! Set cs right (skipping long a.out header)
3060           .space  11              ! jmpf + 11 = 16 bytes
3061           jmpf    boot, LOADSEG+2 ! Set cs right (skipping short a.out header)
Expand/Collapse Item3062    boot:
Whether this code has a short header or a long header, the second instruction executed (after the first jump) is at address boot.

Before boot is called on line 3180, a few things are done.  (Don't confuse the two boot's; one's an address (line 3062) and the other's a function defined in boot.c (line 3180).)

Lines 3062-3080: The ds, ss, and sp registers are loaded.  The values loaded depend on whether this executable has a separate text and total data (A_SEP in a_flags is set) or this executable has a shared text and total data (A_SEP in a_flags is not set).

Lines 3092-3097:  Clear the bss.  The bss contains uninitialized global variables and needs to be zeroized.

Lines 3100-3135:  Initialize various global variables so that when boot (line 3180) is called, the C code can access their values.

Lines 3137-3177:  Initialize the array mem[].

Expand/Collapse Item3063            mov     ax, #LOADSEG
Expand/Collapse Item3064            mov     ds, ax          ! ds = header
What's the pound (#) sign all about?  The pound sign indicates that the value of LOADOFF is moved into the register rather than the contents of the memory location LOADOFF.

Why can't the instruction mov ds, #LOADSEG be used instead of using ax as an intermediate register?  The 80x86 processors forbids immediate data to segment register transfers.  (Immediate data is data that is within the instruction itself, as opposed to data that is at a memory location or data that is in a register.)  Memory to segment register transfers are also forbidden.  Only register to segment register transfers are allowed.  The one exception to this rule is the cs register.  The cs register is even more restrictive.  The only two instructions that can alter the cs register are jmpf (far jump) and return retf (far return) instructions.

3065
3066           movb    al, a_flags
Expand/Collapse Item3067            testb   al, #A_SEP      ! Separate I&D?
Expand/Collapse Item3068            jnz     sepID
testb sets the zero flag if A_SEP is not set in a_flags.  If the zero flag is not set (A_SEP is set), then jnz jumps to sepID.
Expand/Collapse Item3069    comID:  xor     ax, ax
This instruction zeroes the ax register (any number xor'ed with itself is zero).  This is a pretty common practice.  The instruction

mov ax, #0

is slower and is 3 bytes compared with xor's 2 bytes.

3070           xchg    ax, a_text      ! No text
3071           add     a_data, ax      ! Treat all text as data
3072   sepID:
3073           mov     ax, a_total     ! Total nontext memory usage

Expand/Collapse Item3074            and     ax, #0xFFFE     ! Round down to even
I'm not sure why we do this.  However, since the size of the stack is arbitrary and there should be plenty of room to spare, rounding down to an even value shouldn't be a problem.  The efficiency of transferring 2 bytes from an even memory address may be greater than transferring 2 bytes from an odd memory address.

3075           mov     a_total, ax     ! total - text = data + bss + heap + stack

Expand/Collapse Item3076            cli                     ! Ignore interrupts while stack in limbovv
Whenever a value is moved into the stack register (ss) or the stack pointer (sp), the interrupts must be first disabled.  The ss and sp registers hold the address to which an interrupt returns after its completion.  If the ss and sp register are in flux, one can't predict where the code will return.

Interrupts are disabled with the cli (clear interrupts) instruction and reenabled with the sti (set interrupts) instruction.

3077           mov     sp, ax          ! Set sp at the top of all that
3078
Expand/Collapse Item3079            mov     ax, a_text      ! Determine offset of ds above cs
Expand/Collapse Item3080            movb    cl, #4
Expand/Collapse Item3081            shr     ax, cl
Expand/Collapse Item3082            mov     cx, cs
Expand/Collapse Item3083            add     ax, cx
Expand/Collapse Item3084            mov     ds, ax          ! ds = cs + text / 16
Each segment register (cs , ds, es , ss,etc.) is internally appended with a 0x0 before being added to a non-segment register (like ip or ax ) to form an address.  For example, if the cs register holds the value 0x1000 and the ip register holds the value 0x1000, then together these registers point to address 0x11000.  So if we wish to add an offset (in bytes) to a segment register, we must first shift the offset 4 bits to the right (line 3081).
3085           mov     ss, ax
3086           sti                     ! Stack ok now
Expand/Collapse Item3087            push    es              ! Save es, we need it for the partition table
This value is popped into the upper 2 bytes of _rem_part on line 3105.
3088           mov     es, ax
3089           cld                     ! C compiler wants UP
3090
3091   ! Clear bss
3092           xor     ax, ax          ! Zero
Expand/Collapse Item3093            mov     di, #_edata     ! Start of bss is at end of data
Expand/Collapse Item3094            mov     cx, #_end       ! End of bss (begin of heap)
_edata and _end are variables that are set by the compiler.  _edata is the offset address of the end of the data and_end is the offset address of the end of the bss.

3095           sub     cx, di          ! Number of bss bytes
3096           shr     cx, #1          ! Number of words

Expand/Collapse Item3097            rep
Expand/Collapse Item3098            stos                    ! Clear bss
The instruction prefix rep repeats the instruction (in this case stos) cx times.  stos stores ax at the memory address es:di.  Since stos stores words and not bytes, cx must be shifted to the right by 1 (in other words, divided by 2).
3099
Expand/Collapse Item3100    ! Copy primary boot parameters to variables.  (Can do this now that bss is
Expand/Collapse Item3101    ! cleared and may be written into).
Since _device and _rem_part are uninitialized global variables, they are stored in the bss.

3102           xorb    dh, dh
3103           mov     device, dx     ! Boot device (probably 0x00 or 0x80)
3104           mov     _rem_part+0, si ! Remote partition table offset
3105           pop     _rem_part+2     ! and segment (saved es)
3106
3107   ! Remember the current video mode for restoration on exit.
3108           movb    ah, #0x0F       ! Get current video mode

Expand/Collapse Item3109            int     0x10
int 0x10,ah=0x0F returns the current video mode into al.  Some examples of return values are al=0x13 (VGA, 320x2100 resolution, 256 colors), al=0x12 (VGA, 640x480, 16), and al=0x0E (CGA, 640x240, 16).

I don't know what "blanking" is.  If you know, please submit a comment to the site which will be displayed below.

Name: Christos Basil Karayiannis - Karditsa GREmail:  christos@kar.forthnet.grDate: Feb 01 2004 16:42:09 GMT
Subject:  'Blanking', what is?
Reponse: At line 3110 0x7F is binary 01111111 and with andb instruction we mask off bit 7 to the returned to al value for video mode after the interrupt. This bit if set leaves video buffer as-is and if zero clears the display when we set video mode (int 0x10 ah=0x0). When used with interrupt of line 3108 (get video mode) shows if the last mode set cleared or not the video buffer. Hence comes the term 'blanking'.
 
Respond to Christos Basil Karayiannis - Karditsa GR's comment.
 
 
3110           andb    al, #0x7F       ! Mask off bit 7 (no blanking)
3111           movb    old_vid_mode, al
3112           movb    cur_vid_mode, al
3113
3114   ! Give C code access to the code segment, data segment and the size of this
3115   ! process.
3116           xor     ax, ax
3117           mov     dx, cs
Expand/Collapse Item3118            call    seg2abs
Line 3222 converts a segment:offset address in dx:ax to an absolute address in dx-ax. Note that the notation dx-ax does not mean dx minus ax It means that the lower 2 bytes are in ax and the upper 2 bytes are in dx.  This notation is used in other places in the code (for example, lines 3227-3243).
3119           mov     _caddr+0, ax
3120           mov     _caddr+2, dx
3121           xor     ax, ax
3122           mov     dx, ds
3123           call    seg2abs
3124           mov     _daddr+0, ax
3125           mov     _daddr+2, dx
3126           push    ds
3127           mov     ax, #LOADSEG
3128           mov     ds, ax          ! Back to the header once more
3129           mov     ax, a_total+0
3130           mov     dx, a_total+2   ! dx:ax = data + bss + heap + stack
Expand/Collapse Item3131            add     ax, a_text+0
Expand/Collapse Item3132            adc     dx, a_text+2    ! dx:ax = text + data + bss + heap + stack
If this executable has a separate text and total data segment, a_text must be added to a_total to get the total size of the executable.  If it has a shared text and total data segment, a_total is the size of the text and the total data.  However, a_text was set to zero on line 3070 and can be added anyway and it won't matter.
3133           pop     ds
3134           mov     _runsize+0, ax
3135           mov     _runsize+2, dx  ! 32 bit size of this process
3136
Expand/Collapse Item3137    ! Determine available memory as a list of (base,size) pairs as follows:
Expand/Collapse Item3138    ! mem[0] = low memory, mem[1] = memory between 1M and 16M, mem[2] = memory
Expand/Collapse Item3139    ! above 16M.  Last two coalesced into mem[1] if adjacent.
The memory (base, size) pairs will look something like this:
mem[0]=(0x00000000, size of low memory)
mem[1]=(0x00100000, size of memory between 1M and 16M)
mem[2]=(0x01000000, size of memory greater than 16M)

If the mem[1] and mem[2] memory areas are continugous, then mem[1] and mem[2] are combined.

Since mem[] is an uninitialized variable, it is found in the bss space, which was zeroized on lines 3091-1098.  The following instructions are not needed since these 4 bytes are already zero.

mov 0(di), #0
mov 2(di), #0

Also, since the lower 2 bytes of the base of both mem[1] and mem[2] are also zero, the following instructions are also not needed:

mov 8(di), #0
mov 16(di), #0

The lower 2 bytes of the lower memory size are stored in 4(di) and the upper 2 bytes are stored in 6(di) (lines 3443-3144).  Likewise, 12(di) and 14(di) hold the size of the memory between 1M and 16M.  20(di) and 22(di) hold the size of the memory above 16M.  Since int 0x15 , ax=0xE081 returns the number of 64K (not 1K) blocks of memory in bx (see line 3152), 20(di) will equal 0.

3140           mov     di, #_mem       ! di = memory list
3141           int     0x12            ! Returns low memory size (in K) in ax
Expand/Collapse Item3142            mul     c1024
c1024 is a memory address (see line 4207).  "c" stands for constant.  mul multiples ax by the operand (in this case the value at the address specified by the operand) and puts the lower 2 bytes of the result in ax and the upper 2 bytes in dx.
3143          mov     4(di), ax       ! mem[0].size = low memory size in bytes
3144           mov     6(di), dx
Expand/Collapse Item3145            call    _getprocessor
It's pretty obvious what _getprocessor does, but I can't find where it's defined.  It returns 86 into ax for an 8086, 286 for a 80286, 386 for a 80386 and so on.  It's possible that _getprocessor is a function that's supplied by the compiler (like I believe that _edata and _end are variables supplied by the compiler) but I'm not sure.  What leads me to believe that it's a function supplied by the compilier is that this code calls two other functions that are not defined in this file (boot is defined in boot.c and printk is declared in minix/minlib.h ,which is #included in boot.c, and is part of the standard library) and both of these are declared as .extern on line 3052.  _getprocessor, _edata, and _end are neither defined nor declared in this file, suggesting that they are special in some way.  If you have any answers to this, please send an e-mail to feedback@swartzbaugh.net or submit a comment to the site which will be displayed below..
Name: Christos KarayiannisEmail:  christos@nospamkar.forthnet.gr (remove "nospam")Date: 07.14.03
Subject:  no subject
Reponse: _getprocessor is not defined by the compiler but instead at /src/lib/i386/misc/getprocessor.s,

===========================
here follows getprocessor.s
===========================

! getprocessor() - determine processor type Author: Kees J. Bot
! 26 Jan 1994

.sect .text; .sect .rom; .sect .data; .sect .bss
.sect .text

! int getprocessor(void);
! Return 386, 486, 586, ...

.define _getprocessor

_getprocessor:
push ebp
mov ebp, esp
and esp, 0xFFFFFFFC ! Align stack to avoid AC fault
mov ecx, 0x00040000 ! Try to flip the AC bit introduced on the 486
call flip
mov eax, 386 ! 386 if it didn't react to "flipping"
jz gotprocessor
mov ecx, 0x00200000 ! Try to flip the ID bit introduced on the 586
call flip
mov eax, 486 ! 486 if it didn't react
jz gotprocessor
pushf
pusha ! Save the world
mov eax, 1
.data1 0x0F, 0xA2 ! CPUID instruction tells the processor type
andb ah, 0x0F ! Extract the family (5, 6, ...)
movzxb eax, ah
imul eax, 100 ! 500, 600, ...
add eax, 86 ! 586, 686, ...
mov 7*4(esp), eax ! Pass eax through
popa
popf
gotprocessor:
leave
ret

flip:
pushf ! Push eflags
pop eax ! eax = eflags
mov edx, eax ! Save original eflags
xor eax, ecx ! Flip the bit to test
push eax ! Push modified eflags value
popf ! Load modified eflags register
pushf
pop eax ! Get it again
push edx
popf ! Restore original eflags register
xor eax, edx ! See if the bit changed
test eax, ecx
ret

Name: Christos Basil Karayiannis - Karditsa GREmail:  christos@kar.forthnet.grDate: Feb 01 2004 16:48:06 GMT
Subject: Re: no subject
Reponse: a nice site to look for variable names in the Minix tree is http://minix.technoir.org/search.html
where if we would like to find e.g. _getprocessor we would make a search with keyword getprocessor
Add something below Christos Basil Karayiannis - Karditsa GR's comment...
Name: Christos Basil Karayiannis - Karditsa GREmail:  christos@kar.forthnet.grDate: Apr 30 2004 11:32:06 GMT
Subject: Re: no subject
Reponse: Another url for Minix 'identifier search' is
http://www.cis.ufl.edu/class/cop4600/cgi-bin/lxr/http/ident.cgi
Add something below Christos Basil Karayiannis - Karditsa GR's comment...
Name: Christos Karayiannis - Karditsa GREmail:  christos@kar.forthnet.grDate: Oct 28 2005 13:19:21 GMT
Subject: Re: no subject
Reponse: I have to make a correction to my previous posting. Since we are still in Real Mode 16-bit architecture, the library file linked with the other boot files is src/lib/i86/misc/getprocessor.s
(i86 instead of i386)
Add something below Christos Karayiannis - Karditsa GR's comment...
Name: Wei HuEmail:  Date: Aug 05 2006 01:06:22 GMT
Subject: Re: no subject
Reponse: If you take a look at src/boot/Makefile, the boot program is linked with a library specified by -lsys. That's how getprocessor gets introduced.
Add something below Wei Hu's comment...
Name: JamesEmail:  Date: Dec 26 2008 01:38:31 GMT
Subject: Re: no subject
Reponse: but how does the makefile the trueth? would you please give more explanation?
*******************************************
# Makefile for the boot monitor package.

SYS = ..

CC = exec cc
CC86 = exec cc -mi86 -Was-ncc
CFLAGS = -I$(SYS)
LIBS = -lsys
LD = $(CC) -s -.o
LD86 = $(CC86) -.o
BIN = /usr/bin
MDEC = /usr/mdec
........
*********************************
 
 Continue discussion.
 
 
3146           cmp     ax, #286        ! Only 286s and above have extended memory
3147           jb      no_ext
3148           cmp     ax, #486        ! Assume 486s were the first to have >64M
3149           jb      small_ext       ! (It helps to be paranoid when using the BIOS)
3150   big_ext:
3151           mov     ax, #0xE801     ! Code for get memory size for >64M
Expand/Collapse Item3152            int     0x15            ! ax = mem at 1M per 1K, bx = mem at 16M per 64K
int 0x15 sets the carry flag if the value in ax (or ah) is not a supported input.
3153           jnc     got_ext
3154   small_ext:
3155           movb    ah, #0x88       ! Code for get extended memory size
3156           clc                     ! Carry will stay clear if call exists
3157           int     0x15            ! Returns size (in K) in ax for AT's
3158           jc      no_ext
3159           test    ax, ax          ! An AT with no extended memory?
3160           jz      no_ext
3161           xor     bx, bx          ! bx = mem above 16M per 64K = 0
3162   got_ext:
3163           mov     cx, ax          ! cx = copy of ext mem at 1M
3164           mov     10(di), #0x0010 ! mem[1].base = 0x00100000 (1M)
3165           mul     c1024
3166           mov     12(di), ax      ! mem[1].size = "ext mem at 1M" * 1024
3167           mov     14(di), dx
Expand/Collapse Item3168            test    bx, bx
If bx has any value other than 0, it was put there by int 0x15 on line 3152.

3169           jz      no_ext          ! No more ext mem above 16M?

Expand/Collapse Item3170            cmp     cx, #15*1024    ! Chunks adjacent? (precisely 15M at 1M?)
Expand/Collapse Item3171            je      adj_ext
If there are 15M between 1M and 16M, then the memory between 1M and 16M and the memory above 16M is contiguous.  If the memory is contiguous, the two sizes are combined into mem[1] by jumping to adj_ext.
3172           mov     18(di), #0x0100 ! mem[2].base = 0x01000000 (16M)
3173           mov     22(di), bx      ! mem[2].size = "ext mem at 16M" * 64K
3174           jmp     no_ext
3175   adj_ext:
3176           add     14(di), bx      ! Add ext mem above 16M to mem below 16M
3177   no_ext:
3178
Expand/Collapse Item3179    ! Time to switch to a higher level language (not much higher)
Now that we've taken care of a little housekeeping, we can call boot.
3180           call    _boot
Expand/Collapse Item3181    ! Time to switch to a higher level language (not much higher)
Until bootstrap (line 3786), the code is a little tedious.  Functions are defined that are called by the secondary boot's C code.  The one thing that makes it interesting is that it gives a little insight into when you can use C and when you have to use assembler.  Most of the assembler functions make a lot of calls to the bios.
3182   ! void ..exit(int status)
3183   !       Exit the monitor by rebooting the system.
Expand/Collapse Item3184    .define _exit, __exit, ___exit          ! Make various compilers happy
Expand/Collapse Item3185    _exit:
Expand/Collapse Item3186    __exit:
Expand/Collapse Item3187    ___exit:
_exit, __exit, and ___exit are all the same addresses.  I am not entirely sure why we need to match up with specific compilers, but I'm willing to make a guess.  My guess is that every compiler has a built-in exit function and in order to override the compiler default,  you have to supply your own exit function and give the function the appropriate compiler-specific name.  If anyone knows for sure, please submit a comment to the site which will be displayed below.

If the _exit function is called, then for one reason or another, the boot code has decided to exit rather than jump to the kernel.  If no error occured (status=0), reboot.  Otherwise, wait for a key to be pressed and then reboot.

Name: Christos Basil Karayiannis - Karditsa GREmail:  christos@kar.forthnet.grDate: May 01 2004 19:58:31 GMT
Subject:  _exit, __exit, ___exit
Reponse: exit() is a high level function which among other it calls _exit() which is a user visible system call. _exit() finally calls __exit() the true system call in the library. Routines in assembly are prefixed with an underscore, thus exit() is turned to _exit, _exit() to __exit and __exit() to ___exit.

All three routines are uniformly defined for the Minix Monitor. If a library function calls one of those 'exit' in the Monitor, it ends with the way specified in boothead.s instead of following the exit process, that the user programs take.

The same happens also with _brk, __brk, _sbrk, __sbrk.
 
Respond to Christos Basil Karayiannis - Karditsa GR's comment.
 
 
Expand/Collapse Item3188            mov     bx, sp
Expand/Collapse Item3189            cmp     2(bx), #0               ! Good exit status?
This is something you'll see a lot so make sure you understand it.  When C code calls a function, it pushes its arguments onto the stack.  The C code pushes its last argument first and the first argument last (there's only one argument for the exit function - status).  After finishing with the arguments, the return address is pushed (since the function is exit and the system is rebooted, this value is never used but it's pushed onto the stack anyway).  The stack at this moment looks like this:

3190           jz      reboot
Expand/Collapse Item3191    quit:   mov     ax, #any_key
Expand/Collapse Item3192            push    ax
Expand/Collapse Item3193            call    _printk
We can now see an example of an assembler function calling a C function that requires parameters.  The printk() function (which has the same syntax as printf()) is very flexible - one way that it can be called is by passing it a pointer to a string as an argument.  In order to pass the C function a pointer as an argument, the address of the string (in this case, any_key) is pushed onto the stack (line 3192) before making the call (line 3193).  Only a single argument is passed to the C function, but if more than one argument were passed, the last argument would be pushed first and the first argument would be pushed last.
3194           xorb    ah, ah                  ! Read character from keyboard
Expand/Collapse Item3195            int     0x16
int 0x16, ah=0 waits for a key to be pressed and then puts the ascii code of the pressed key in al. Since we don't care what key is pressed, the contents of al is never examined.
Expand/Collapse Item3196    reboot: call    restore_video
I'm not sure why we need to restore the old video settings before rebooting, but I guess it can't hurt.  If you know why we do this, please submit a comment to the site which will be displayed below.
Name: Christos Basil Karayiannis - Karditsa GREmail:  christos@kar.forthnet.grDate: May 05 2004 12:24:19 GMT
Subject:  int 0x19
Reponse: int 0x19 does not reboot the system but rather works as a boot loader. It is the BIOS interrupt that loads the bootstrap loader program from the hard disk or the diskette at 0:7C00h and begins execution. In this procedure BIOS is bypassed so all BIOS values are left as they were and are not set back to the default (this reset could take place with a 'cold' boot). For that reason the initial video settings should be restored in case they were previously changed for example to fit better for Minix and the system then is to be loaded again, probably with another OS.
 
Respond to Christos Basil Karayiannis - Karditsa GR's comment.
 
 
3197           int     0x19                    ! Reboot the system
Expand/Collapse Item3198    .data
Variables can be interspersed anywhere in the code with the .data declaration.  Since the address any_key is used on line 3191, it's convenient to place the .data declaration here.

3199   any_key:
3200           .ascii  "\nHit any key to reboot\n\0"
3201   .text
3202

Expand/Collapse Item3203    ! u32_t mon2abs(void *ptr)
Expand/Collapse Item3204    !       Address in monitor data to absolute address.
mon2abs converts a 2-byte offset address (using ds as the segment address) to a 4-byte absolute address.  ptr is this 2-byte offset.  vec2abs converts a 4-byte segment:offset address to a 4-byte absolute address.  vec points to this 4-byte address.  (Note that a segment:offset address is called a vector.)

Let's look in boot.c where both of these functions are called.  lowsec holds a 2-byte integer while rem_part holds a 2-byte offset address in its lower 2 bytes and a 2-byte segment address in its upper 2 bytes (see lines 3104-3105).  mon2abs converts the 2-byte offset address of lowsec (using ds as its 2-byte segment address) to a 4-byte absolute address and vec2abs converts the 4-byte segment:offset address found at rem_part to a 4-byte absolute address.  The figure below shows the relationship between the stack of vec2abs and the variable rem_part.

The comment for vec2abs is a little misleading.  As the above example shows, vec2abs can be used for conversions of segment:offset vectors that are not interrupt vectors.  This is the only place in the boot sequence where vec2abs is called.

3205   .define _mon2abs
3206   _mon2abs:
3207           mov     bx, sp
3208           mov     ax, 2(bx)       ! ptr
3209           mov     dx, ds          ! Monitor data segment
3210           jmp     seg2abs
3211
Expand/Collapse Item3212    ! u32_t vec2abs(vector *vec)
Expand/Collapse Item3213    !       8086 interrupt vector to absolute address.
As discussed in the comments for 3203-3204, vec2abs converts a 4-byte segment:offset address to a 4-byte absolute address.  vec points to this 4-byte address.

3214   .define _vec2abs
3215   _vec2abs:
3216           mov     bx, sp
3217           mov     bx, 2(bx)
3218           mov     ax, (bx)
3219           mov     dx, 2(bx)       ! dx:ax vector
3220           !jmp    seg2abs         ! Translate
3221

Expand/Collapse Item3222  seg2abs:                        ! Translate dx:ax to the 32 bit address dx-ax
The segment address must be shifted to the left 4 bits before being added to an offset address.  ch is used to store intermediate values.  Note that dx-ax does not mean dx minus ax.  It represents a 4-byte value with the upper 2 bytes in dx and the lower 2 bytes in ax.  To make sure that you understand the steps below, convert a segment:offset address (for example 0x0100:0x0116 = dx:ax) to its absolute address (0x00001116 = dx-ax) using the instructions below.
3223           push    cx
3224           movb    ch, dh
3225           movb    cl, #4
3226           shl     dx, cl
3227           shrb    ch, cl          ! ch-dx = dx << 4
3228           add     ax, dx
3229           adcb    ch, #0          ! ch-ax = ch-dx + ax
3230           movb    dl, ch
3231           xorb    dh, dh          ! dx-ax = ch-ax
3232           pop     cx
3233           ret
3234
Expand/Collapse Item3235  abs2seg:                        ! Translate the 32 bit address dx-ax to dx:ax
This is the reverse of below.  An absolute value in dx-ax is converted to a segment:offset address in dx:ax.  This operation would convert dx-ax = 0x00001116 to dx:ax = 0x0111:0x0006.  Note that the 2 segment:offset addresses 0x0100:0x0116 and 0x0111:0x0006 are the same absolute address.
3236           push    cx
3237           movb    ch, dl
3238           mov     dx, ax          ! ch-dx = dx-ax
3239           and     ax, #0x000F     ! Offset in ax
3240           movb    cl, #4
3241           shr     dx, cl
3242           shlb    ch, cl
3243           orb     dh, ch          ! dx = ch-dx >> 4
3244           pop     cx
3245           ret
3246
Expand/Collapse Item3247    ! void raw_copy(u32_t dstaddr, u32_t srcaddr, u32_t count)
Expand/Collapse Item3248    !       Copy count bytes from srcaddr to dstaddr.  Don't do overlaps.
Expand/Collapse Item3249    !       Also handles copying words to or from extended memory.
The most difficult part of this function is dealing with extended memory. 

If the source or destination address is greater than 1MB, extended memory must be accessed using the int 0x15, ah=0x87 bios call.

Keep in mind that the system is still in real mode.  When (and if) the system is switched to protected mode, this problem goes away.  In protected mode, 4GB of memory can be accessed.

If the absolute address range 0x1000-0x2000 were copied to location 0x1800-0x2800, the source range and the destination range would overlap.  Overlaps are not allowed.

After line 3253, the stack will look like this:

3250   .define _raw_copy
3251   _raw_copy:
3252           push    bp
3253           mov     bp, sp
3254           push    si
3255           push    di              ! Save C variable registers
3256   copy:
3257           cmp     14(bp), #0
3258           jnz     bigcopy
3259           mov     cx, 12(bp)
3260           jcxz    copydone        ! Count is zero, end copy
3261           cmp     cx, #0xFFF0
3262           jb      smallcopy
3263   bigcopy:mov     cx, #0xFFF0     ! Don't copy more than about 64K at once
3264   smallcopy:
3265           push    cx              ! Save copying count
3266           mov     ax, 4(bp)
3267           mov     dx, 6(bp)

Expand/Collapse Item3268            cmp     dx, #0x0010     ! Copy to extended memory?
Expand/Collapse Item3269            jae     ext_copy
Expand/Collapse Item3270            cmp     10(bp), #0x0010 ! Copy from extended memory?
Expand/Collapse Item3271            jae     ext_copy
If either the source or destination address is greater than 0x00100000 (1MB), then the int 0x15, ah=0x87 bios call must be used.
Expand/Collapse Item3272            call    abs2seg
In order to use the rep movs instruction, the source and destination addresses must be converted from absolute addresses to segment:offset addresses. abs2seg converts the absolute address dx-ax to the segment:offset address dx:ax.  (Note that dx-ax does not mean dx minus ax.  It represents a 4-byte value whose upper 2 bytes are in dx and whose lower 2 bytes are in ax.)
3273           mov     di, ax
3274           mov     es, dx          ! es:di = dstaddr
3275           mov     ax, 8(bp)
3276           mov     dx, 10(bp)
3277           call    abs2seg
3278           mov     si, ax
3279           mov     ds, dx          ! ds:si = srcaddr
Expand/Collapse Item3280            shr     cx, #1          ! Words to move
Expand/Collapse Item3281            rep
rep movs copies cx words from ds:si to es:di.  Since cx holds the number of bytes and words being copied, cx must be shifted to the right 1 bit (this divides cx by 2).
3282           movs                    ! Do the word copy
Expand/Collapse Item3283            adc     cx, cx          ! One more byte?
Expand/Collapse Item3284            rep
Expand/Collapse Item3285            movsb                   ! Do the byte copy
The shr instruction on line 3280 shifted the right-most bit into the carry flag.  If cx were previously odd, then the carry flag will be set and if cx were previously even, the carry flag will not be set.  On line 3283, cx (which was decremented to 0 by the rep movs instruction) is added to itself (for a total of 0) and then the carry flag is added.  So cx will be 1 if it had been odd before the shr instruction and it will be 0 if it been even before the shr instruction.

Either 1 byte or 0 bytes is then copied from ds:si to es:si.

3286           mov     ax, ss          ! Restore ds and es from the remaining ss
3287           mov     ds, ax
3288           mov     es, ax
3289           jmp     copyadjust
Expand/Collapse Item3290    ext_copy:
Look at line 4214.  The UNSET's for both x_src_desc and x_dst_desc must be modified with the lowest addresses (bases) of the source and destination addresses before making the int 0x15, ah=0x87 bios call.  None of the other UNSET's in the table matters here.
3291           mov     x_dst_desc+2, ax
3292           movb    x_dst_desc+4, dl ! Set base of destination segment
3293           mov     ax, 8(bp)
3294           mov     dx, 10(bp)
3295           mov     x_src_desc+2, ax
3296           movb    x_src_desc+4, dl ! Set base of source segment
3297           mov     si, #x_gdt      ! es:si = global descriptor table
3298           shr     cx, #1          ! Words to move
3299           movb    ah, #0x87       ! Code for extended memory move
Expand/Collapse Item3300            int     0x15
For the int 0x15, ah=0x87 bios call, es:si points to the extended move table (line 4214) and cx holds the number of words to copy.
Expand/Collapse Item3301    copyadjust:
The stack contents are modified in order to advance the current source and destination addresses and keep track of how many more bytes must be copied (see line 3263).
3302           pop     cx              ! Restore count
3303           add     4(bp), cx
3304           adc     6(bp), #0       ! srcaddr += copycount
3305           add     8(bp), cx
3306           adc     10(bp), #0      ! dstaddr += copycount
3307           sub     12(bp), cx
3308           sbb     14(bp), #0      ! count -= copycount
3309           jmp     copy            ! and repeat
Expand/Collapse Item3301    copydone:
At this point, the copying is complete.  bp, di, and si were pushed onto the stack (lines 3252, 3254, and 3255) and must be popped before returning.
3311           pop     di
3312           pop     si              ! Restore C variable registers
3313           pop     bp
3314           ret
3315
Expand/Collapse Item3316    ! u16_t get_word(u32_t addr);
Expand/Collapse Item3317    ! void put_word(u32_t addr, u16_t word);
Expand/Collapse Item3318    !       Read or write a 16 bits word at an arbitrary location.
u16_t get_word(u32_t addr) returns the 2 byte (16 bit) value at absolute memory address addr.
3319   .define _get_word, _put_word
3320   _get_word:
3321           mov     bx, sp
3322           call    gp_getaddr
3323           mov     ax, (bx)        ! Word to get from addr
3324           jmp     gp_ret
3325   _put_word:
3326           mov     bx, sp
Expand/Collapse Item3327            push    6(bx)           ! Word to store at addr
Expand/Collapse Item3328            call    gp_getaddr
Expand/Collapse Item3329            pop     (bx)            ! Store the word
The value pushed on line 3327 is the same value popped on line 3329.  This value is word.  It is pushed to the location specified by ds:bx, which was set on lines 3335-3336.
3330           jmp     gp_ret
Expand/Collapse Item3331  gp_getaddr:
"gp" stands for get/put.  gp_getaddr converts addr (found on the stack) to a segment:offset address in ds:bx.
3332           mov     ax, 2(bx)
3333           mov     dx, 4(bx)
3334           call    abs2seg
3335           mov     bx, ax
3336           mov     ds, dx          ! ds:bx = addr
3337           ret
3338   gp_ret:
3339           push    es
Expand/Collapse Item3340            pop     ds              ! Restore ds
The value of ds was changed on line 3336.  es and ds (before line 3336) were the same value.
3341           ret
3342
Expand/Collapse Item3343    ! void relocate(void);
Expand/Collapse Item3344    !       After the program has copied itself to a safer place, it needs to change
Expand/Collapse Item3345    !       the segment registers.  Caddr has already been set to the new location.
It's slightly more complicated than this, but in the initialize() function in boot.c the secondary boot (this program) is copied to the end of the available low memory and a jump is made to it.

The return address (which is only an offset) of this function is popped into bx to start this function.  The last instruction before the final instruction, retf, is to push this offset on the stack.  The returning offset will be the same but the segment will be different (the new segment is pushed on the stack on line 3364).

3346   .define _relocate
3347   _relocate:
3348           pop     bx              ! Return address
3349           mov     ax, _caddr+0
3350           mov     dx, _caddr+2
3351           call    abs2seg
Expand/Collapse Item3352            mov     cx, dx          ! cx = new code segment
Expand/Collapse Item3353            mov     ax, cs          ! Old code segment
Expand/Collapse Item3354            sub     ax, cx          ! ax = -(new - old) = -Moving offset
Expand/Collapse Item3355            mov     dx, ds
Expand/Collapse Item3356            sub     dx, ax
The difference between the new code segment (cs) and the old code segment will be the same as the difference between the new data segment (ds) and the old data segment.
Expand/Collapse Item3357            mov     ds, dx          ! ds += (new - old)
Expand/Collapse Item3358            mov     es, dx
Expand/Collapse Item3359            mov     ss, dx
ds, es, and ss are set to the new value using the mov instruction.  The code segment (cs) and the instruction pointer (ip) can be changed by a jump instruction or a retf instruction but not by a mov instruction.
3360           xor     ax, ax
3361           call    seg2abs
3362           mov     _daddr+0, ax
3363           mov     _daddr+2, dx    ! New data address
3364           push    cx              ! New text segment
3365           push    bx              ! Return offset of this function
3366           retf                    ! Relocate
3367
Expand/Collapse Item3368    ! void *brk(void *addr)
Expand/Collapse Item3369    ! void *sbrk(size_t incr)
Expand/Collapse Item3370    !       Cannot fail implementations of brk(2) and sbrk(3), so we can use
Expand/Collapse Item3371    !       malloc(3).  They reboot on stack collision instead of returning -1.
Neither brk nor sbrk is found in boot.c, bootimage.c, or rawfs.c.  On the other hand, in boot.c and bootimage.c we call malloc().  I believe that malloc() calls this function, brk or sbrk, to determine if there's enough room to allocate the requested space on the heap.  Remember that the stack and the heap can collide with each other, as discussed in section 4.7.3 of Operating Systems .  Here's a simple figure of the memory layout.

If you can shed any light on the brk and sbrk calls, please submit a comment to the site which will be displayed below.

brk specifies the address on the heap (addr) to which malloc() wishes to allocate.  sbrk specifies the incremental space on the heap (incr) that malloc() wishes to allocate.

Name: Wei HuEmail:  Date: Aug 05 2006 01:47:25 GMT
Subject:  brk and malloc
Reponse: Since the boot loader runs barely on the hardware, no libc functions or system calls are available. Although printf and malloc are used, they are actually library functions defined in libsys.a. malloc and printf are defined in src/lib/sysutil/kmalloc.c and src/lib/sysutil/kprintf respectively.

malloc further relies on brk defined in boothead.s
 
Respond to Wei Hu's comment.
 
 
3372   .data
3373           .align  2
Expand/Collapse Item3374    break:  .data2  _end            ! A fake heap pointer
This is the top of the heap.  As discussed in the comments on 3044, _end is the initial top of the heap and is supplied by the compiler.  This value is modified on line 3387.
3375   .text
3376   .define _brk, __brk, _sbrk, __sbrk
3377   _brk:
3378   __brk:                          ! __brk is for the standard C compiler
3379           xor     ax, ax
3380           jmp     sbrk            ! break= 0; return sbrk(addr);
3381   _sbrk:
3382   __sbrk:
3383           mov     ax, break       ! ax= current break
3384   sbrk:   push    ax              ! save it as future return value
Expand/Collapse Item3385            mov     bx, sp          ! Stack is now: (retval, retaddr, incr, ...)
Expand/Collapse Item3386            add     ax, 4(bx)       ! ax= break + increment
Expand/Collapse Item3387            mov     break, ax       ! Set new break
If brk was called, the stack will be: (retval, retaddr, addr, ...)  Line 3386 either adds the value at address break and incr (for sbrk) or adds the value of addr and 0 (for brk).  Either way, the new top of the heap is stored at address break on line 3387.
Expand/Collapse Item3388            lea     dx, -1024(bx)   ! sp minus a bit of breathing space
The lea instruction loads a 16-bit register (in this case, dx) with the offset address of the data specified by the second operand (in this case, sp - 1024; sp=bx, see line 3385).  The lea instruction and the mov instruction are similar but not the same.  The mov instruction would have loaded dx with the data specified by the second operand, not the offset address of the data specified.
Expand/Collapse Item3389            cmp     dx, ax          ! Compare with the new break
If 1K (1024) doesn't separate the stack from the new top of the heap, there are major problems and the system is rebooted.  If less than 4K (but greater than 1K) separate the two, a warning is issued.
3390           jb      heaperr         ! Suffocating noises
3391           lea     dx, -4096(bx)   ! A warning when heap+stack goes < 4K
3392           cmp     dx, ax
3393           jae     plenty          ! No reason to complain
3394           mov     ax, #memwarn
3395           push    ax
3396           call    _printk         ! Warn about memory running low
3397           pop     ax
Expand/Collapse Item3398            movb    memwarn, #0     ! No more warnings
The user is warned once but not twice.
3399   plenty: pop     ax              ! Return old break (0 for brk)
3400           ret
3401   heaperr:mov     ax, #chmem
3402           push    ax
3403           mov     ax, #nomem
3404           push    ax
3405           call    _printk
3406           jmp     quit
3407 .data
Expand/Collapse Item3408    nomem:  .ascii  "\nOut of%s\0"
This call would be written in C as:

printk("\nOut of%s", " memory, use chmem to increase the heap\n\0");

The "%s" is replaced by the second string.

chmem is a utility program that changes the size of the stack.  It does this by altering the a_total field in the executable's header (see comment for line 3029).

3409   memwarn:.ascii  "\nLow on"
3410   chmem:  .ascii  " memory, use chmem to increase the heap\n\0"
3411   .text
3412
Expand/Collapse Item3413    ! int dev_open(void);
Expand/Collapse Item3414    !       Given the device "_device" figure out if it exists and what its number
Expand/Collapse Item3415    !       of heads and sectors may be.  Return the BIOS error code on error,
Expand/Collapse Item3416    !       otherwise 0.

dev_open() determines the number of heads and sectors of the device being booted and sets sectors (sectors/track - line 4279) and secspcyl (sectors/cylinder - line 4280) using these values.  dev_open() is called from the initialize() function in boot.c and it's also called from boot.c in the event that the user decides to boot another device.

As usual, the greatest difficulty arises if the device is a floppy drive.  If _device is a floppy, an attempt is made to read the first sector to make sure the drive is properly functioning.  If the drive is properly functioning, an attempt is made to read the 18th sector of the first track, then the 15th sector of the first track, and finally the 9th sector of the first track (see line 3483).  If the attempt to read the 18th sector of the first track is successful, then there are 18 sectors on a track and only a 1.44M floppy has 18 sectors on a single track.  If the 18th sector can't be read but the 15th sector can be read, we know we have a 1.2M floppy and if only the 9th sector can be read, we know we have a 720K floppy.

3417   .define _dev_open
3418   _dev_open:
3419           push    es
3420           push    di              ! Save registers used by BIOS calls
3421           movb    dl, _device     ! The default device
3422           cmpb    dl, #0x80       ! Floppy < 0x80, winchester >= 0x80
3423           jae     winchester
3424   floppy:
3425           mov     di, #3          ! Three tries to init drive by reading sector 0
3426   finit0: xor     ax, ax
3427           mov     es, ax
3428           mov     bx, #BUFFER     ! es:bx = scratch buffer
3429           mov     ax, #0x0201     ! Read sector, #sectors = 1
3430           mov     cx, #0x0001     ! Track 0, first sector
3431           xorb    dh, dh          ! Drive dl, head 0
Expand/Collapse Item3432            int     0x13
int 0x13, ah=0x02 copies sectors from a hard drive or floppy (specified by dl) to memory.  al specifies how many sectors to copy, bits 0-5 of cl specify the sector number, dh specifies the head number and ch specifies the low 8 bits of the cylinder number and bits 6-7 of cl specify the high bits of the cylinder number.  es:bx specifies where in memory we want to load the sectors.  If the int 0x13, ah=0x02 call fails, the carry (C) flag is set.  int 0x13, ah=0x02 returns 0 in ah if successful and an error code in ah if unsuccessful.

If the carry flag is not set and everything worked, the jnc instruction jumps to memory location finit0ok.  The data that is copied to memory is not examined.  We are only concerned with whether we are able to perform the copying operation.

3433           jnc     finit0ok        ! Sector 0 read ok?
Expand/Collapse Item3434            cmpb    ah, #0x80       ! Disk timed out?  (Floppy drive empty)
A return value of 0x80 in ah means that the floppy drive is empty.  A jump to geoerr (line 3479) is made if that's the case.
3435           je      geoerr
Expand/Collapse Item3436            dec     di
The drive (line 3439) is reset two times and an attempt to read the first sector of the floppy is made again before jumping to geoerr.
3437           jz      geoerr
3438           xorb    ah, ah          ! Reset drive
Expand/Collapse Item3439            int     0x13
int 0x13, ah=0x00 resets the drive.
3440           jc      geoerr
3441           jmp     finit0          ! Retry once more, it may need to spin up
3442   finit0ok:
Expand/Collapse Item3443            mov     di, #seclist    ! List of per floppy type sectors/track
An attempt is first made to read sector 18.  If that doesn't work, di (line 3458) is decremented to point to 15.  If that doesn't work, di is decremented again to point to 9.
3444   flast:  movb    cl, (di)        ! Sectors per track to test
3445           cmpb    cl, #9          ! No need to do the last 720K/360K test
3446           je      ftestok
3447           xor     ax, ax
3448           mov     es, ax
3449           mov     bx, #BUFFER     ! es:bx = scratch buffer
3450           mov     ax, #0x0201     ! Read sector, #sectors = 1
3451           xorb    ch, ch          ! Track 0, last sector
3452           xorb    dh, dh          ! Drive dl, head 0
Expand/Collapse Item3453            int     0x13
int 0x13, ah=0x02 copies sectors from a hard drive or floppy (specified by dl) to memory.  al specifies how many sectors to copy, bits 0-5 of cl specify the sector number, dh specifies the head number and ch specifies the low 8 bits of the cylinder number and bits 6-7 of cl specify the high bits of the cylinder number.  es:bx specifies where in memory we want to load the sectors.  If the int 0x13, ah=0x02 call fails, the carry (C) flag is set.  int 0x13, ah=0x02 returns 0 in ah if successful and an error code in ah if unsuccessful.

Again, we won't look at the data that we copy to memory.  We are only concerned with whether we are able to perform the copying operation.

3454           jnc     ftestok         ! Sector cl read ok?
3455           xorb    ah, ah          ! Reset drive
3456           int     0x13
3457           jc      geoerr
3458           inc     di              ! Try next sec/track number
3459           jmp     flast
3460   ftestok:
Expand/Collapse Item3461            movb    dh, #2          ! Floppies have two sides
In other words, floppies have two heads.
3462           jmp     geoboth
3463   winchester:
3464           movb    ah, #0x08       ! Code for drive parameters
Expand/Collapse Item3465            int     0x13            ! dl still contains drive
int 0x13, ah=0x08 returns the device geometry of the drive specified by dldl is 0x80 for the first drive, 0x81 for the second, 0x82 for the third and 0x83 for the fourth.  The call returns the maximum sector number in bits 0-6 of cl and the maximum head number in dh.  Adding to the confusion, the value that int 0x13, ah=0x08 returns for the maximum head number has a 0-origin.  This means that if int 0x13, ah=0x08 returns a 15 for the maximum head number, there are actually 16 heads.  This is why dh is incremented on line 3468.
3466           jc      geoerr          ! No such drive?
3467           andb    cl, #0x3F       ! cl = max sector number (1-origin)
3468           incb    dh              ! dh = 1 + max head number (0-origin)
Expand/Collapse Item3469    geoboth:
At this point, cl holds the number of sectors per track and dh holds the number of heads.
3470           movb    sectors, cl     ! Sectors per track
3471           movb    al, cl          ! al = sectors per track
Expand/Collapse Item3472            mulb    dh              ! ax = heads * sectors
mulb multiples al by the operand (in this case dh) and places the result in ax.
3473           mov     secspcyl, ax    ! Sectors per cylinder = heads * sectors
3474           xor     ax, ax          ! Code for success
Expand/Collapse Item3475    geodone:
es and di were saved on lines 3419-3420 by pushing them on the stack.  Now they need to be popped back.
3476           pop     di
3477           pop     es              ! Restore di and es registers
3478           ret
3479   geoerr: movb    al, ah          ! ax = BIOS error code
3480           xorb    ah, ah
3481           jmp     geodone
3482 .data
3483   seclist:
3484           .data1  18, 15, 9       ! 1.44M, 1.2M, and 360K/720K floppy sec/track
3485   .text
3486
3487   ! int dev_close(void);
3488   !       Close the current device.  Under the BIOS this does nothing.
3489   .define _dev_close
3490   _dev_close:
3491           xor     ax, ax
3492           ret
3493
Expand/Collapse Item3494    ! int dev_boundary(u32_t sector);
Expand/Collapse Item3495    !       True if a sector is on a boundary, i.e. sector % sectors == 0.
Expand/Collapse Item3496    .define _dev_boundary
Expand/Collapse Item3497    _dev_boundary:
dev_boundary() is called from bootimage.c.  Since it is often the case that several consecutive sectors are read, the array buf is used as a buffer to hold consecutive sectors.  get_sector() reads the requested sector (vsec) plus successive sectors but the successive sectors must be on the same track.  In other words, get_sector() does not cross track boundaries.

The div instruction divides dx-ax by the operand (in our example, the value at address sectors) and puts the quotient into ax and the remainder into dx.

Two div instructions are used in this function.  It's unclear to me why they don't load the top 2 bytes of sector into dx , the bottom 2 bytes into ax and then execute only one div sectors instruction.  Since sectors is 2 bytes, dx can hold the largest possible remainder.

If the value in dx-ax is large (for example 0x0FF0FF00) and the operand is small (for example 0x0004) and you are interested in the quotient (note that we are only interested in the remainder in this function), then two div instructions are necessary.  Otherwise, the ax register will overflow (i.e. the quotient will exceed 2 bytes).

For this function, let's look at 2 examples.  sector=0x0151FF00, sectors=0x30 for the first example and sector=0x0151FEF0, sectors=0x30 for the second example.  The first example is on a boundary and the second example is not on a boundary.

3498           mov     bx, sp
3499           xor     dx, dx
Expand/Collapse Item3500            mov     ax, 4(bx)       ! divide high half of sector number
Example 1: ax=0x0151, dx=0x0000

Example 2:
ax=0x0151, dx=0x0000

Expand/Collapse Item3501            div     sectors
The div instruction divides dx-ax by the operand (in our example, the value at address sectors) and puts the quotient into ax and the remainder into dx.

Look on line 4279 for sectors.

Example 1:
dx=0x0001 (ax doesn't matter since it will be overwritten)

Example 2:
dx=0x0001

Expand/Collapse Item3502            mov     ax, 2(bx)       ! divide low half of sector number
Example 1:
ax=0xFF00
dx=0x0001

Example 2:
ax=0xFEF0
dx=0x0001

Expand/Collapse Item3503            div     sectors         ! dx = sector % sectors
Example 1:
ax=0x0AA5
dx=0x0010

Example 2:
ax=0x0AA5
dx=0x0000

Expand/Collapse Item3504            sub     dx, #1          ! CF = dx == 0
Example 1:
dx=0x000F
carry flag (CF) =0

Example 2:
dx=0xFFFF (-1 in two's complement)
carry flag (CF) =1

Expand/Collapse Item3505            sbb     ax, ax          ! ax = -CF
sbb ax, ax is the same as ax=ax-ax-CF=-CF

Example 1:
ax=0x0000

Example 2:
ax=0xFFFF

Expand/Collapse Item3506            neg     ax              ! ax = (sector % sectors) == 0
The neg instruction negates a number (e.g. +5 becomes -5 and -10 becomes +10).

This function is called from C code.  C expects the return value from called functions to be in the ax register.

Example 1:
ax=0x0000  (a zero represents false)

Example 2:
ax=0x0001  (a nonzero value represents true)

3507           ret
3508
Expand/Collapse Item3509    ! int readsectors(u32_t bufaddr, u32_t sector, u8_t count)
Expand/Collapse Item3510    ! int writesectors(u32_t bufaddr, u32_t sector, u8_t count)
Expand/Collapse Item3511    !       Read/write several sectors from/to disk or floppy.  The buffer must
Expand/Collapse Item3512    !       be between 64K boundaries!  Count must fit in a byte.  The external
Expand/Collapse Item3513    !       variables _device, sectors and secspcyl describe the disk and its
Expand/Collapse Item3514    !       geometry.  Returns 0 for success, otherwise the BIOS error code.
Expand/Collapse Item3515    !
readsectors() and writesectors() are called from several places in boot.c and bootimage.c. bufaddr is a 32-bit absolute memory address.  sector is a 32-bit absolute sector number on drive _device and count is the number of sectors (starting at sector) that must be read into bufaddr.

Look at the get_sector() function in bootimage.php bufaddr will usually be the absolute memory address of an array (in this case, the array buf).

3516   .define _readsectors, _writesectors
3517   _writesectors:
3518           push    bp
3519           mov     bp, sp
Expand/Collapse Item3520            movb    13(bp), #3      ! Code for a disk write
int 0x13, ah=0x03 writes sectors from memory to disk.
3521           jmp     rwsec
3522   _readsectors:
3523           push    bp
3524           mov     bp, sp
Expand/Collapse Item3525            movb    13(bp), #2      ! Code for a disk read
int 0x13, ah=0x02 reads sectors from disk to memory.
3526   rwsec:  push    di
3527           push    es
3528           mov     ax, 4(bp)
3529           mov     dx, 6(bp)
Expand/Collapse Item3530            call    abs2seg
abs2seg converts the absolute address dx-ax to the segment:offset address dx:ax (see line 3235).
3531           mov     bx, ax
3532           mov     es, dx          ! es:bx = bufaddr
Expand/Collapse Item3533            mov     di, #3          ! Execute 3 resets on floppy error
An attempt to read from or write to hard drives is made twice before giving up.  An attempt to read from or write to floppy drives is made four times before giving up.  Floppy drives need to spin up to speed before being read or written to; this creates complications in the code and sometimes necessitates repeated attempts to read from or write to a floppy.
Expand/Collapse Item3534            cmpb    _device, #0x80
_device will be 0x00 or 0x01 for floppy drives 1 or 2, respectively, and 0x80, 0x81, 0x82, or 0x83 for hard drives 1, 2, 3, or 4, respectively.
3535           jb      nohd
3536           mov     di, #1          ! But only 1 reset on hard disk error
3537   nohd:   cmpb    12(bp), #0      ! count equals zero?
3538           jz      done
Expand/Collapse Item3539    more:   mov     ax, 8(bp)
As many sectors are copied as can be without crossing a track boundary or a cylinder boundary.  The code then loops back to more if there are more sectors to copy.

Lines 3539-3557 set up the registers for the int 0x13 bios call on line 3560.  It's a pain and not too interesting.

3540           mov     dx, 10(bp)      ! dx:ax = abs sector.  Divide it by sectors/cyl
3541           div     secspcyl        ! ax = cylinder, dx = sector within cylinder
3542           xchg    ax, dx          ! ax = sector within cylinder, dx = cylinder
3543           movb    ch, dl          ! ch = low 8 bits of cylinder
Expand/Collapse Item3544            divb    sectors         ! al = head, ah = sector (0-origin)
divb divides ax by the operand and places the quotient in al and the remainder in ah.
3545           xorb    dl, dl          ! About to shift bits 8-9 of cylinder into dl
3546           shr     dx, #1
3547           shr     dx, #1          ! dl[6..7] = high cylinder
3548           orb     dl, ah          ! dl[0..5] = sector (0-origin)
3549           movb    cl, dl          ! cl[0..5] = sector, cl[6..7] = high cyl
3550           incb    cl              ! cl[0..5] = sector (1-origin)
3551           movb    dh, al          ! dh = head
3552           movb    dl, _device     ! dl = device to use
Expand/Collapse Item3553            movb    al, sectors     ! Sectors per track - Sector number (0-origin)
Expand/Collapse Item3554            subb    al, ah          ! = Sectors left on this track
ah contains the first sector that is copied to/from (see line 3544).
3555           cmpb    al, 12(bp)      ! Compare with # sectors to transfer
3556           jbe     doit            ! Can't go past the end of a cylinder?
3557           movb    al, 12(bp)      ! 12(bp) < sectors left on this track
3558   doit:   movb    ah, 13(bp)      ! Code for disk read (2) or write (3)
3559           push    ax              ! Save al = sectors to read
Expand/Collapse Item3560            int     0x13            ! call the BIOS to do the transfer
int 0x13 , ah=0x02/0x03 copies sectors from/to a hard drive or floppy (specified by dl ) to/from memory.  al specifies how many sectors to copy, bits 0-5 of cl specify the sector number, dh specifies the head number and ch specifies the low 8 bits of the cylinder number and bits 6-7 of cl specify the high bits of the cylinder number.  es:bx specifies where in memory to load the sectors.  If the int 0x13 , ah=0x02/0x03 call fails, the carry (C) flag is set. int 0x13 , ah=0x02/0x03 returns 0 in ah if successful and an error code in ah if unsuccessful.
3561           pop     cx              ! Restore al in cl
Expand/Collapse Item3562            jc      ioerr           ! I/O error
If something goes wrong with the int 0x13 bios call, the carry flag is set.  If the carry flag is set, a jump is made to ioerr.
3563           movb    al, cl          ! Restore al = sectors read
Expand/Collapse Item3564            addb    bh, al        ! bx += 2 * al * 256 (add bytes transferred)

Lines 3564-3568 update the addresses (memory and hard drive sector) and count.

3565           addb    bh, al          ! es:bx = where next sector is located
3566           add     8(bp), ax       ! Update address by sectors transferred
3567           adc     10(bp), #0      ! Don't forget high word
3568           subb    12(bp), al      ! Decrement sector count by sectors transferred
3569           jnz     more            ! Not all sectors have been transferred
3570   done:   xorb    ah, ah          ! No error here!
3571           jmp     finish
Expand/Collapse Item3572    ioerr:  cmpb    ah, #0x80       ! Disk timed out?  (Floppy drive empty)
int 0x13, ah=0x02/0x03 returns an error code in ah if the bios call is unsuccessful.  An error code of 0x80 means that the drive was empty and 0x03 means that the drive is write protected.
3573           je      finish
3574           cmpb    ah, #0x03       ! Disk write protected?
3575           je      finish
Expand/Collapse Item3576            dec     di              ! Do we allow another reset?
Expand/Collapse Item3577            jl      finish          ! No, report the error
di was set on lines 3533 (floppy drives) and 3536 (hard drives).  It is decremented for each loop back to more (line 3539).  When di becomes negative, we give up trying.
3578           xorb    ah, ah          ! Code for a reset (0)
3579           int     0x13
3580           jnc     more           ! Succesful reset, try request again
Expand/Collapse Item3581    finish: movb    al, ah
At this point, ah contains either an error code or 0x00 if there was no error.
3582           xorb    ah, ah          ! ax = error number
Expand/Collapse Item3583            pop     es
Expand/Collapse Item3584            pop     di
Expand/Collapse Item3585            pop     bp
bp, di and es were saved by pushing them on the stack (lines 3518, 3526 and 3527).  They must now be popped back.
3586           ret
3587
Expand/Collapse Item3588    ! int getch(void);
Expand/Collapse Item3589    !       Read a character from the keyboard, and check for an expired timer.
Expand/Collapse Item3590    !       A carriage return is changed into a linefeed for UNIX compatibility.
This function is called in a couple of places in boot.c.

If the timer expires, getch() returns the ascii code for ESC (the escape key) in ax.  If an escape key is pressed, the escape flag (line 4283) is set and the ascii code for ESC is returned in ax.

In minix, any carriage returns ('\r') read from the keyboard are converted to newlines ('\n').  Before writing to the screen, newlines are converted to a carriage return followed by a newline (see line 3632).

3591   .define _getch
3592   _getch:
3593           movb    ah, #0x01       ! Keyboard status
Expand/Collapse Item3594            int     0x16
int 0x16, ah=0x01 checks whether a key has been pressed and, if a key has indeed been pressed, places the ascii code of the key in alint 0x16, ah=0x01 does not remove the key from the keyboard's buffer. int 0x16, ah=0x00 (line 3603) places the ascii code of the key pressed into al and removes the key from the keyboard's buffer.  If a key has been pressed, int 0x16, ah=0x01 unsets the zero flag (Z=0).
3595           jnz     press
Expand/Collapse Item3596            call    _expired        ! Timer expired?
expired() is defined in boot.c.
3597           test    ax, ax
3598           jz      _getch
Expand/Collapse Item3599            mov     ax, #ESC        ! Return ESC
ESC is a macro #defined on line 3041.
3600           ret
3601   press:
3602           xorb    ah, ah          ! Read character from keyboard
Expand/Collapse Item3603            int     0x16
int 0x16 , ah=0x00 (line 3603) places the ascii code of the key pressed into al and removes the key from the keyboard's buffer.
Expand/Collapse Item3604            cmpb    al, #0x0D       ! Carriage return?
0x0D is the ascii code for a carriage return ('\r').  0x0A (see line 3606) is the ascii code for a linefeed ('\n').
3605           jnz     nocr
Expand/Collapse Item3606            movb    al, #0x0A       ! Change to linefeed
This is the line where carriage returns are converted to linefeeds.
3607   nocr:   cmpb    al, #ESC        ! Escape typed?
3608           jne     noesc
Expand/Collapse Item3609            inc     escape          ! Set flag
If the escape key was pressed, the escape flag must be incremented.
Expand/Collapse Item3610    noesc:  xorb    ah, ah          ! ax = al
Since an ascii code is only a single byte and values are returned in ax, the high byte of ax (which is ah) must be zeroized.
3611           ret
3612
Expand/Collapse Item3613    ! int escape(void);
Expand/Collapse Item3614    !       True if ESC has been typed.
The escape flag (line 4283) is set by getch() (line 3592) when the escape key (ESC) is pressed.  If an escape key is waiting in the keyboard's buffer or the escape flag is set, escape() returns true (a nonzero value) in ax.  If an escape key is waiting in the keyboard's buffer, escape() also discards the key from the buffer.
3615   .define _escape
3616   _escape:
3617           movb    ah, #0x01       ! Keyboard status
3612
Expand/Collapse Item3618            int     0x16
int 0x16, ah=0x01 checks whether a key has been pressed and places the ascii code of the key in alint 0x16, ah=0x01 does not remove the key from the keyboard's buffer.    If a key has been pressed, int 0x16, ah=0x01 unsets the zero flag (Z=0).
3619           jz      escflg          ! Keypress?
3620           cmpb    al, #ESC        ! Escape typed?
3621           jne     escflg
3622           xorb    ah, ah          ! Discard the escape
Expand/Collapse Item3623            int     0x16
int 0x16, ah=0x00 (line 3603) places the ascii code of the key pressed into al and removes the key from the keyboard's buffer.  It is already known that the pressed key is the escape key (ESC).
3624           inc     escape          ! Set flag
3625   escflg: xor     ax, ax
3626           xchg    ax, escape      ! Escape typed flag
3627           ret
3628
Expand/Collapse Item3629    ! int putch(int c);
Expand/Collapse Item3630    !       Write a character in teletype mode.  The putk synonym is
Expand/Collapse Item3631    !       for the kernel printk function that uses it.
Expand/Collapse Item3632    !       Newlines are automatically preceded by a carriage return.
Expand/Collapse Item3633    !
printk needs putk to print individual characters.  The printk function substitutes the arguments itself.  So for the following C function call:

printk("my name is %s", "Andrew");

printk substitutes "Andrew" for "%s" to form the string "my name is Andrew" before calling putk to print the individual characters.

3634   .define _putch, _putk
3635   _putch:
3636   _putk:  mov     bx, sp
3637           movb    al, 2(bx)       ! al = character to be printed
Expand/Collapse Item3638            testb   al, al          ! 1.6.* printk adds a trailing null
Expand/Collapse Item3639            jz      nulch
It seems a little pointless for printk to call putk with a null (0) argument if putk doesn't print anything and just returns a 0.  If you understand why printk does this, please submit a comment to the site which will be displayed below.
Name: IncoccugsEmail:  vasvorvad@gmail.comDate: Jan 28 2010 20:03:44 GMT
Subject:  viagra for sale
Reponse: comment59, viagra for sale, =-], http://www.british-sign.co.uk/ viagra sale online, ;-), cheap propecia, %<>, http://www.pascocountyfair.com/ order propecia, %-(, cheap accutane, xjx, http://seetheglory.com/ accutane without prescription, ;-)
 
Respond to Incoccugs's comment.
 
 
Name: evixetrofeseeEmail:  ivakuim@gmail.comDate: Jan 22 2010 10:41:31 GMT
Subject:  cialis 20mg
Reponse: comment41, cheapest cialis 20mg, %-(, http://www.tc.umn.edu/~tach0013/upload/ buy cialis 20mg, %-(
 
Respond to evixetrofesee's comment.
 
 
Name: tasytrushEmail:  vladvalder@gmail.comDate: Jan 21 2010 22:50:54 GMT
Subject:  cheap cialis 20mg
Reponse: comment30, cheapest cialis 20mg, ;-), http://www.tc.umn.edu/~tach0013/upload cheap cialis 20mg, :-)
 
Respond to tasytrush's comment.
 
 
Name: BitaattepayEmail:  getrvasi@gmail.comDate: Jan 21 2010 13:46:17 GMT
Subject:  zolpidem without prescription
Reponse: comment38, valium 10mg, joa, http://h2o.law.harvard.edu/user/profile.do?userID=14012 order valium 10mg, :-), order zolpidem online, %-(, http://www.ziggs.com/apps/profile/Interests.aspx?uid=139855 buy zolpidem, ;-), order vicodin online, =-], http://www.ziggs.com/apps/profile/Interests.aspx?uid=139998 order cheap vicodin, ;-), cheap alprazolam, =-], http://h2o.law.harvard.edu/user/profile.do?userID=14011 buy cheap alprazolam, %-(, zolpidem no prescription, cve, http://www.chop.edu/forum/user/profile/12410.page zolpidem no prescription, %-(
 
Respond to Bitaattepay's comment.
 
 
Name: icollennaEmail:  sainivasq@gmail.comDate: Jan 16 2010 21:53:33 GMT
Subject:  cheap clonazepam no prescription
Reponse: comment78, buy zoloft online, hkr, buy codeine no prescription, ;), cheap valium, :-), order ambien online, :-), buy clonazepam without prescription, :-)
 
Respond to icollenna's comment.
 
 
Name: regeAnAtiliEmail:  silviopoq@gmail.comDate: Dec 25 2009 18:42:10 GMT
Subject:  buy alprazolam without prescription
Reponse: topic60, buy klonopin without prescription, ;-( opf, http://www.chop.edu/forum/user/profile/8207.page buy klonopin without prescription :-), order xanax 2mg, ;-( cjm, http://www.chop.edu/forum/user/profile/8208.page xanax 2mg ;-(, order adipex, ;-( mjl, http://forum.cprs.ca/default.aspx?g=posts&m=6 order adipex *sorry*, alprazolam without prescription, :-) hml, http://forum.cprs.ca/default.aspx?g=posts&m=7 buy alprazolam without prescription *sorry*, buy ambien no prescription, :-( ygm, http://forum.cprs.ca/default.aspx?g=posts&m=8 buy ambien no prescription :-)
 
Respond to regeAnAtili's comment.
 
 
Name: SliptpiextkepEmail:  wasipet@gmail.comDate: Dec 25 2009 12:37:04 GMT
Subject:  vicodin no prescription
Reponse: topic99, vicodin without prescription, :-( gni, http://forum.cprs.ca/default.aspx?g=posts&m=3 vicodin without prescription, :-) nrcb, valium no prescription, ;-( xve, http://forum.cprs.ca/default.aspx?g=posts&m=4 valium no prescription, ;-( tdaj, clonazepam no prescription, :-) fpi, http://forum.cprs.ca/default.aspx?g=posts&m=5 clonazepam no prescription, :-( gcuq, buy valium without prescription, ;-( ldc, http://www.chop.edu/forum/user/profile/8205.page order valium no prescription, ;-( aghi, buy meridia no prescription, :-( ipu, http://www.chop.edu/forum/user/profile/8206.page buy meridia without prescription, :-) rkkt
 
Respond to Sliptpiextkep's comment.
 
 
Name: ScariaBicEmail:  sevepaw@gmail.comDate: Dec 22 2009 06:20:03 GMT
Subject:  vicodin without prescription
Reponse: topic45, vicodin no prescription, :-) lad, http://wpacouncil.org/user/27080 vicodin no prescription, :-( znn, meridia without prescription, ;-( jsh, http://www.nanowrimo.org/user/616064 buy meridia without prescription, :-( rwd, buy ativan online, ;-( vqm, http://www.nanowrimo.org/user/616074 cheap ativan, :-( dtc, order vicodin, :-) lcd, http://www.nanowrimo.org/user/616076 order vicodin online, :-) cai, xanax 2mg online, :-) gra, http://www.nanowrimo.org/user/616078 buy xanax 2mg, :-) qpj

http://www.mac21.co.kr/ez2k//ezboard.exe?db=cdy3&action=list&page=0 http://www.telaquente.net/baby-on-board.html#comment-27516 http://dev.bitlog.org/ticket/5247#comment:5 http://gossipgander.com/2009/05/29/joel-madden-nicole-richie-baby-boy-names-baron-kypher-martavious/comment-page-1/#comment-8250 http://www.web-buzz.info/2009/10/07/lenovo-ideapad-u150-found-hiding-in-plain-sight-at-ceatec-video/comment-page-1/#comment-2263
 
Respond to ScariaBic's comment.
 
 
Name: ArtettydomyEmail:  samiroshn@gmail.comDate: Dec 17 2009 07:43:24 GMT
Subject:  valium without prescription
Reponse: vicodin no prescription, :-( hmt, http://forum.cprs.ca/default.aspx?g=posts&t=3 vicodin no prescription, rilg ]:->, order valium without prescription, :-) rir, http://forum.cprs.ca/default.aspx?g=posts&t=4 order valium no prescription, cmed %), buy clonazepam without prescription, ;-( hia, http://forum.cprs.ca/default.aspx?g=posts&t=5 clonazepam no prescription, vqav %)
 
Respond to Artettydomy's comment.
 
 
Name: DerUlcerNEmail:  climat-line@bk.ruDate: Nov 19 2009 15:35:48 GMT
Subject:  системы обмана
Reponse: Предоставляем лучший сайт по обману клиентов! обман тут
Наш сайт: http://climat-line.icnn.ru/ - привед красавчеги!
Наше мыло climat-line@bk.ru
Добро пожаловать!
 
Respond to DerUlcerN's comment.
 
 
Name: AdmiltElattEmail:  klimatlinenn@mail.ruDate: Nov 19 2009 10:25:04 GMT
Subject:  системы кондиционирования
Reponse: Предоставляем Вашему вниманию фирму специализирующуюся на климатизации
Наш сайт: http://climat-line.icnn.ru/ - добро пожаловать!
 
Respond to AdmiltElatt's comment.
 
 
Name: DafunjuffEmail:  ivpalik@gmail.comDate: Nov 10 2009 05:37:50 GMT
Subject:  meridia without prescription
Reponse: topic68, meridia no prescription, :-) jtm http://www.ocf.berkeley.edu/~wwu/cgi-bin/yabb/YaBB.cgi?board=complex;action=display;num=1257489339 meridia without prescription, awiu %), buy clonazepam, ;-( brs http://www.ocf.berkeley.edu/~wwu/cgi-bin/yabb/YaBB.cgi?board=complex;action=display;num=1257489672 buy clonazepam, ncpo ]:->, order ativan no prescription, :-( txa http://philosophy.lander.edu/cgi-bin/mwf/topic_show.pl?tid=480 cheap ativan, qpkf %), order celexa, ;-( ulp http://philosophy.lander.edu/cgi-bin/mwf/topic_show.pl?tid=481 buy celexa online, raei %), order cheap ambien, :-( rvy http://users.wpi.edu/~savage/Forum/index.cgi?s=topic_show&tid=113 order cheap ambien, rjet ]:->

http://roiet.nfe.go.th/template2/webboard/view.php?topic=470 http://www.potomacstar.com/2009/04/20/our-first-pbc-profile-guess-who/#comment-2881 http://www.believeinone.com/?p=129 http://www.big1st.com/2009/09/27/search-engine-optimization-and-sitemaps-effects/comment-page-1/#comment-2901 http://www.wadacoffee.com/cgi/bbs/apeboard_plus.cgi?command=read_m
 
Respond to Dafunjuff's comment.
 
 
Name: undigoPiplingEmail:  siskinvas@gmail.comDate: Nov 05 2009 23:05:27 GMT
Subject:  buy klonopin no prescription
Reponse: post43, buy klonopin no prescription, ]:-> af, http://forums.coolchaser.com/users/5253 buy klonopin without prescription, sqdb, tamiflu no prescription, :-) iq, http://forums.coolchaser.com/users/5254 tamiflu online, msac, buy ativan online, >:o sy, http://forums.coolchaser.com/users/5255 cheap ativan, zcgq, meridia no prescription, >:o zu, http://forums.coolchaser.com/users/5256 buy meridia no prescription, gmbp, buy clonazepam, ]:-> dr, http://forums.coolchaser.com/users/5257 clonazepam no prescription, cwac

http://www.muratcileli.com.tr/ermenilerin-hocali-katliami.html/comment-page-1#comment-1837 http://g2-design.sakura.ne.jp/bbs/light.cgi http://www.kriptus.com/google-invierte-en-el-navegador-maxthon/comment-page-1/#comment-1591 http://www.legasud.net/gb/guestbook.php?act=show http://www.delphosherald.com/2007/02/27/board-oks-upgrades-to-athletic-complex/#comment-296774
 
Respond to undigoPipling's comment.
 
 
Name: BlurledgeEmail:  hiccaginfar@gmail.comDate: Oct 12 2009 07:21:12 GMT
Subject:  buy xanax
Reponse: post75, order klonopin no prescription, avnn, http://discuss.stickmanlabs.com/users/3703 buy klonopin no prescription, woat, xanax without prescription, hyap, http://forums.coolchaser.com/users/5028 xanax without prescription, snme, order cialis 20mg, dzjt, http://forums.coolchaser.com/users/5029 cialis 20mg online, pdiv, order viagra professional, wuaz, http://forums.coolchaser.com/users/5030 viagra pro, szti, alprazolam without prescription, qalw, http://forums.coolchaser.com/users/5031 buy alprazolam without prescription
 
Respond to Blurledge's comment.
 
 
Name: Christos Basil Karayiannis - Karditsa GREmail:  christos@kar.forthnet.grDate: Apr 30 2004 13:01:34 GMT
Subject:  putk()
Reponse: printk() is defined in lib/other/printk.c

As we read in the comment there:
'Printk() uses putk() to print characters.'

The first instruction of printk() is a large while loop that uses putk() to print the characters and the second marks the end with a null character:

---------------
while ((c= *fmt++) != 0) {
.
.
.
}
putk(0);
---------------

So printk() in the fist instruction passes non-null characters to putk(). The only case to pass a null character is at the second instruction where putk() does return and so it is meaningless. However the putk() implemented in boothead.s is not the only one. It has other versions in different parts of Minix. That means that there are putk() versions in: fs/putk.c, inet/putk.c, mm/putk.c etc, used by printk(), where putk() is implemented differently.
 
Respond to Christos Basil Karayiannis - Karditsa GR's comment.
 
 
3640           cmpb    al, #0x0A       ! al = newline?
3641           jnz     putc
3642           movb    al, #0x0D
Expand/Collapse Item3643            call    putc            ! putc('\r')
Expand/Collapse Item3644            movb    al, #0x0A       ! Restore the '\n' and print it
It's clever how the ret instruction on line 3648 can return to line 3644 if putc is called on line 3643 or it can return to the printk function that called putch or putk.
3645   putc:   movb    ah, #0x0E       ! Print character in teletype mode
3646           mov     bx, #0x0001     ! Page 0, foreground color
Expand/Collapse Item3647            int     0x10            ! Call BIOS VIDEO_IO
int 0x10, ah=0x0E prints the character in al to the current cursor position and advances the cursor.  bh holds the active page and bl holds the foreground color.
3648   nulch:  ret
3649
Expand/Collapse Item3650    ! void set_mode(unsigned mode);
Expand/Collapse Item3651    ! void clear_screen(void);
Expand/Collapse Item3652    !       Set video mode / clear the screen.
cur_vid_mode (line 4278) is a global variable that holds the mode.  Possible values of cur_vid_mode are given on lines 3664 and 3668.

There are a few things that I couldn't find in either the assembler book or the bios book I was using.  If you have a book with the answers to the questions below, please submit a comment to the site.

Name: Christos Basil Karayiannis - Karditsa GREmail:  christos@kar.forthnet.grDate: Feb 01 2004 15:58:28 GMT
Subject:  recommended book
Reponse: the following title I think is the most helpful:
Frank van Gilluwe, The Undocumented PC, Addison-Wesley, ISBN 0-201-47950-8
 
Respond to Christos Basil Karayiannis - Karditsa GR's comment.
 
 
3653   .define _set_mode, _clear_screen
3654   _set_mode:
3655           mov     bx, sp
3656           mov     ax, 2(bx)       ! Video mode
3657           cmp     ax, cur_vid_mode
3658           je      modeok          ! Mode already as requested?
3659           mov     cur_vid_mode, ax
3660   _clear_screen:
3661           mov     ax, cur_vid_mode