1 <Title>460 Week
1 Notes
</Title> <Body bgcolor=
"#00cccc" text=
"#000000"><H1>460 Lab Assignment #
1</H1><Pre>
2 CS460 Lab Assignment #
1
3 ###########################################################################
4 DUE : Week of Jan
16,
2012
5 ###########################################################################
8 To deveop a boot program for booting the MTX operating system.
10 2. Background Reading List and Timetable:
13 3-
1. Download the MTX image file
14 http://www.eecs.wsu.edu/~cs460/samples/LAB1/mtximage.bin
15 Use it as a VIRTUAL floppy image OR dump it to a REAL floppy disk by
16 dd if=mtximage.bin of=/dev/fd0
17 Then, boot up MTX from the floppy disk.
18 Test run the MTX operating system as demonstrated in class.
20 CONTENTS of the MTX disk image:
22 | B0 | B1 ...................................................... B1339 |
23 --------------------------------------------------------------------------
24 |booter| An EXT2 file system for MTX; kernel=/boot/mtx |
25 --------------------------------------------------------------------------
27 LAB#
1 IS FOR YOU TO WRITE A BOOTER PROGRAM TO REPLACE THE booter IN BLOCK#
0
28 TO BOOT UP THE MTX KERNEL, which is the image file /boot/mtx.
30 3-
2. Download and install the BCC package to YOUR Linux system:
31 http://www.eecs.wsu.edu/~cs460/samples/BCC/
32 Read the HOWTO file for install instructions.
34 3-
3. Background: Computer Architecture and Programming Environment
35 Lab#
1 assumes the following hardware and software environments.
37 Hardware: Intel X86 based PC running Linux. If you don't have such a PC,
38 try to get one or work on the LAB PCs in Sloan
327.
39 Sofware: BCC compiler-assembler-linker under Linux.
41 When a PC starts, it is in the so-called UNPROTECTED mode, also known as
42 the
16-bit mode. In such a mode, the PC's CPU can only execute
16-bit code
43 and access
1 MB of memory. The diagram below shows the
1MB memory layout,
44 shown in
64KB segments.
46 0x0000 0x1000 .......
0x9000 0xA000 ...
0xF000
47 -----------------------------------------------------------
48 | | .......... | | BIOS |
49 -----------------------------------------------------------
50 |<--------------
640KB RAM area --------->|<--- ROM ----->|
52 The CPU's internal registers are
53 segment registers: CS, DS, SS, ES
54 general registers: AX, BX, CX, DX, BP, SI, DI
55 status register : FLAG
57 instruction point or program counter: IP
58 All registers are
16-bit wide.
60 The CPU operates as follows:
61 1. At any given time, the CPU can only access FOUR segments of memory,
62 each segment is
64KB in size and pointed by a segment register:
64 CS -
> Code segment = program code or instructions
65 DS -
> Data segment = static and global data (ONE COPY only)
66 SS -
> Stack segment = stack area for calling and local variables.
67 ES -
> Extra segment = temp area; may be used for malloc()/mfree()
69 2. The CPU executes in an infinite loop:
72 (
1). IP points at the instruction in Code segment of memory;
73 (
2). Fetch instruction (always from Code segment), so the
74 20-bit physical address is (CS<
<4 + IP);
75 (
3). Decode the instruction = (opcode, operands);
76 (
4). If operands are in memory: load operands into CPU
77 (always from Data segment), so the
20-bit physical
78 address is (DS<
<4 + operandAddress)
79 (
5). Execute the instruction, which may change IP (by
80 br, jmp, call, ret) OR SP (by push,pop,call,ret).
81 When SP is used, e.g. in push, pop, call, ret, it's
82 always in the Stack sgement, so the
20-bit physical
83 address is (SS<
<4 + SP).
84 If result must go back to memory, it's again in the
86 (
6). Checking for interrupts OR execution error. If so,
87 start exception processing.
90 3. The number of DISTINCT segments presented to the CPU depends on the
91 memory model of the executing program, which in turn is determined by
92 the compiler and linker used to generate the binary executable image.
93 The most often used memory models are
95 SMALL model (COM files): CS=DS=SS all in ONE segment <=
64KB
96 MEDIUM model (EXE files): CS=CodeSegment, DS=SS=Data+Stack segment
97 (up to
128 KB of execution image size)
99 SMALL memory model programs are easier to maintain, for example, they can
100 be loaded to any segment in memory and setup to run correctly with ease.
101 They are typically used in a simple environment such as during booting.
103 Finally, in order to run a SMALL memory model program, the following steps
105 (
1). A C compiler and assembler that generate
16-bit (object) code
106 (
2). A linker that combines the object code to generate a ONE-segment
107 binary executable image.
108 We shall use BCC under Linux to do (
1) and (
2).
109 (
3). LOAD the binary executable image into memory (at a segment
110 boundary, of course) and set CPU's CS=DS=SS = loaded segment.
111 Set SP at the HIGH end of the segment.
112 Set IP at the beginning instruction in the segment.
113 Then the CPU will execute the image correctly.
115 3-
4. An assembly file bs.s in in the ~cs460/samples/LAB1/ directory.
116 You may download and use it directly.
119 !============================================================================
120 .globl begtext, begdata, begbss ! needed by linker
121 .text ! these tell as:
122 begtext: ! text,data,bss segments
123 .data ! are all the same.
128 !============================================================================
130 BOOTSEG =
0x9000 ! Boot block is loaded again to here.
131 SSP =
8192 ! Stack pointer at SS+
8KB
133 .globl _main,_prints ! IMPORT symbols
134 .globl _getc,_putc,_diskr,_setes,_inces,_error ! EXPORT symbols
136 !-------------------------------------------------------
137 ! Only one SECTOR loaded at (
0000,
7C00). Get entire BLOCK in
138 !-------------------------------------------------------
139 mov ax,#BOOTSEG ! set ES to
0x9000
141 xor bx,bx ! clear BX =
0
142 !---------------------------------------------------
143 ! diskio[
0,
0] to read boot BLOCK to [
0x9000,
0]
144 !---------------------------------------------------
145 xor dx,dx ! drive
0, head
0
147 incb cl ! cyl
0, sector
1
148 mov ax, #
0x0202 ! READ
1 block
151 jmpi start,BOOTSEG ! CS=BOOTSEG, IP=start
154 mov ax,cs ! establish segments again
155 mov ds,ax ! we know ES,CS=
0x8F00. Let DS=CS
156 mov ss,ax ! SS = CS ===
> all point at
0x8F00
158 mov sp,#SSP ! SP =
8KB above
0x90000
160 mov ax,#
0x0012 !
640x480 color
163 call _main ! call main() in C
171 !======================== I/O functions =================================
172 !---------------------------------------------
173 ! char getc() function: returns a char
174 !---------------------------------------------
176 xorb ah,ah ! clear ah
177 int
0x16 ! call BIOS to get a char in AX
180 !----------------------------------------------
181 ! void putc(char c) function: print a char
182 !----------------------------------------------
187 movb al,
4[bp] ! get the char into aL
188 movb ah,#
14 ! aH =
14
189 movb bl,#
0x0D ! bL = cyan color
190 int
0x10 ! call BIOS to display the char
195 !---------------------------------------
196 ! diskr(cyl, head, sector, buf)
198 !---------------------------------------
201 mov bp,sp ! bp = stack frame pointer
203 movb dl, #
0x00 ! drive
0=FD0
204 movb dh,
6[bp] ! head
205 movb cl,
8[bp] ! sector
208 mov bx,
10[bp] ! BX=buf ==
> memory addr=(ES,BX)
209 mov ax, #
0x0202 ! READ
2 sectors to (EX, BX)
211 int
0x13 ! call BIOS to read the block
212 jb _error ! to error if CarryBit is on [read failed]
217 ! void set_es(unsigned short segment) set ES register to segment
226 ! void inces() inc ES by
0x40, or
1KB
233 !------------------------------
235 !------------------------------
248 BCC's C compiler prefix every GLOBAL symbol with an underscore, so that main
249 becomes _main, getc becomes _getc, etc.
250 BCC's assembler uses the same convention for global symbols, which must be
251 declared by the .globl statements in assembly code.
253 As shown, bs.s EXPORTs the following functions
258 void diskr(int cyl, int head, int sector, char *buf)
259 viod setes(int segment);
262 which are callable from C.
264 *********** THE LOGIC OF bs.s IS AS FOLLOWS: *************
266 (
1). It is to be combined with a .c source file to form a booter code
267 which occupies the boot BLOCK (block#
0) of a floppy disk.
269 (
2). During booting, BIOS loads
512 bytes of this boot BLOCK to
270 (
0x0000,
0x7C00) and jumps to it. Although only half in, it can start
271 execution because it does not need any portion that's not yet loaded.
273 (
3). It sets ES=
0x9000, BX=
0 and calls diskr() to load the entire boot
276 (
4). Then it jumps to the symbol start relative to
0x9000, and
277 continues to execute from there. This jump sets CS to
0x9000.
279 (
5). It sets DS,SS to CS, and SP to
8KB above SS. Note that ES is already
280 set to
0x9000 in (
3). Thus, CS,DS,SS and ES all point at the same
281 segment address
0x9000.
283 (
6). It then calls YOUR main() in C, which is specified in
3 below.
285 (
7). Upon return from C code, bs.s checks the return value, which should be
1
286 if no error. If no error, it jumps to (
0x1000,
0) to start up MTX.
287 else; it displays an Error! message and reboot.
291 First, some notes about using BCC's C compiler:
293 (
1). Use identifier names <=
8 chars; the compiler will truncate long names
294 to
8 chars, including the leading _
295 (
2). Declare all variables BEFORE using them (else compile error)!!!!
296 (
3). Declare function parameters OUTSIDE the function heading, e.g.
297 int myfun(x, y) int x; char *y;
300 instead of int myfun(int x, char *y)
303 (You may use the bcc -ansi option to allow ANSI style C statements)
305 (
4). Whenever in doubt, use pretheses to ensure correct precedence, e.g.
306 a = b %
2 +
1; should be written as a = (b %
2) +
1; if that's
309 Other than these, bcc is very good as it produces excellent error
312 Second, never assume that your program will work. More likely, it will NOT.
313 An easy way to TRACE your program execution, especially for debugging, is to
314 use putc('
1'); putc('
2'), etc. in your C code. This way you can easily see
315 where the program stopped working.
317 You must implement the main(), gets() and prints(char *s) functions in C.
318 You may use the C library functions strcmp(), strcpy(), strlen(), etc.
319 as long as they do NOT need the support of an operating system. But you may
320 NOT use printf(), scanf(), putchar(), getchar(), ... because these I/O
321 functions depend on the support of an operating system. During booting,
322 there is NO operating system yet!
324 For PRE-LAB1 work, write YOUR main() function to do the following:
326 (
1). Print a string
"What's your name?".
327 (
2). Read in a name string, e.g.
"John Smith".
328 (
3). Print a string
"Welcome, John Smith!".
329 (
4). If the name string == NULL, print
"bye bye!" and return
1
330 else, loop back to (
1) again.
332 LAB#
1 IS FOR YOU TO MODIFY THIS SIMPLE main() FUNCTION TO ACTUALLY BOOT
333 UP THE MTX OPERATING SYSTEM.
335 4. HOW TO cross COMPILE and LINK under Linux: (Use these as a sh script)
336 --------------------------------------------------------------
341 ld86 -d bs.o main.o /usr/lib/bcc/libc.a
342 echo check a.out size
344 echo dumping a.out to floppy .......
345 dd if=a.out of=/dev/fd0 bs=
1024 count=
1
346 -------------------------------------------------------------
347 The last step dumps (at most
1KB of) a.out to BLOCK
0 of /dev/fd0.
348 The resulting disk should be bootable.
351 ****************************************************************
352 Your a.out must be <=
1024 bytes in order for it to fit in ONE disk block.
354 THERE IS NO FAT IN MY bs.s CODE. The .s type says loud and clear
355 that it's already Slim! If your a.out is too big, it has been eating
356 too much junk food. You must put it on diet until it weighs no more
357 than
1024 pounds (bytes, that is).
358 ****************************************************************
360 5. Compile and link bs.s with YOUR main.c to generate a booter and dump it
361 to BLOCK #
0 of a floppy disk. Boot up from the floppy and make sure your
362 program works correctly.
364 6. How to write YOUR I/O functions:
365 During booting, only BIOS is available for I/O. The getc()/putc() fucntions
366 in bs.s calls BIOS to input a char from beyboard/output a char to display.
368 Use getc() to implement YOUR OWN
370 gets(s) char *s; which inputs a string from the keyboard.
372 NOTE: getc() of BIOS does not echo the input char. YOU must echo the
373 input chars to see the chars. While collecting inputs,char *s MUST have
374 memory space to hold the input chars. From the keyboard,the ENTER key
375 ('\r' in C) signifies the end of an input string.
377 Use putc(c) char c; to implement YOUR own
379 which prints a string to the display.
380 ===============================================================================
382 7. MAIN TASK OF LAB#
1: DUE and DEMO in Week of Jan.
16,
2012
384 7-
1. Refer to the CONTENTS of the MTX disk image:
386 | B0 | B1 ............................ B1339 |
387 ------------------------------------------------
388 |booter| An EXT2 file system for MTX |
389 ------------------------------------------------
391 Block#
0 contains a booter, which can boot up MTX.
392 The remaining parts of the disk is an EXT2 file system (per CS360) with
393 1KB block size. The EXT2 file system contents are
397 -------------------------------------------
399 bin dev etc user sys boot
401 commands devFiles passwd userDirs mtx
402 (bootable MTX kernels)
404 where /boot/mtx is a bootable MTX kernel.
406 Write YOUR main() as follows:
408 (
1). Prompt for filename to boot, e.g. mtx or image, etc. You may assume
409 that all bootable files are in the /boot directory.
410 (
2). Find the file. Recall that
"finding a file amounts to finding its
412 (
3). From the file's inode, find the disk blocks of the file:
413 i_block[
0] to i_block[
11] are DIRECT blocks, and
414 i_blokc[
12] points to INDIRECT blocks.
415 MTX kerenl has at most
64 (
1KB) blocks, so no double-indirect blocks.
417 (
4). Load the blocks of /boot/mtx into memory at the segment
0x1000.
418 (
5). return
1 to bs.s for OK, return
0 for failure.
419 ==========================================================================
420 (
6). If YOUR main() loads the disk blocks of mtx successfully and returns
1
421 bs.s will jump to (
0x1000,
0) to start up MTX.
423 7-
2. How to read a disk block into memory:
425 The function diskr(cyl, head, sector, buf) in bs.s reads a disk block
426 (
2 sectors) at (cyl, head, sector) into memory at the physical address
427 (ES<
<4 + buf), i.e. buf is a VIRTUAL address in the segment pointed by ES.
430 ES -
> Data segment, buf is the address of a global variable in C, then
431 diskr(cyl, head, sector, buf); reads a block into buf;
432 ES -
> 0x2000, buf=
0, then diskr(cyl, head, sector, buf); reads a block
433 to (
0x2000<
<4 +
0), etc.
435 The functions setes(segment); sets ES to any segment,
436 inces(); increment ES by
0x40, which is
1KB.
438 A
1.44MB floppy disk has
80 cylinders,
2 heads per cylinder and
18 sectors
439 under each head. The PHYSICAL layout of a floppy disk is as follows, where
440 cyl, head, sector all count from
0.
442 ----------------------------------------------------------------------
443 |s0 s1 .... s17 | s18 .... s35 | s36 ..... s53|s54 s71| ...
444 ----------------------------------------------------------------------
445 |<-- head
0---->|<--- head
1 -->|<--- head
0 --->|<-- head
1 --->| ....
446 |<--------- ---cyl
0 ---------->|<-------- cyl
1 ------------->| ....
448 A disk block consists of
2 contigious sectors. Given a block number, blk,
449 which counts from
0 to
1339, how to convert blk into (cyl, head, sector)?
450 -------------------------------------------------------------------------
451 Use the Mailman's algorithm (per CS360) to
452 FIGURE OUT THE CONVERSION ALGORITHM YOURSELF
453 -------------------------------------------------------------------------
454 Then write a function
455 get_block(blk, buf) int blk; char buf[];
457 //convert blk to (cyl,head,sector);
458 diskr(cyl, head, sector, buf);
460 which will load the disk block into memory at (ES, buf).