5. c functions engi 3655 lab sessions a unix saleslady, lenore, enjoys work, but she likes the beach...
DESCRIPTION
Richard Khoury3 Assembly Language Processor instructions labelled with mnemonic abbreviations Advantages ◦ Very efficient code ◦ Gives us very low-level control of the computer Disadvantages ◦ Writing large complex programs is very slow ◦ Code not portable; the 80x86 assembly instruction set is only valid on 80x86 CPUs For decades it was believed that “something as complex as an operating system [has] to be written exclusively in assembly language"TRANSCRIPT
5. C FunctionsENGI 3655 Lab Sessions
A UNIX saleslady, Lenore,Enjoys work, but she likes the beach more.She found a good wayTo combine work and play:She sells C shells by the seashore.
Richard Khoury 2
Textbook Readings Operating-System Design and
Implementation◦ Section 2.6
Richard Khoury 3
Assembly Language Processor instructions labelled with
mnemonic abbreviations Advantages
◦ Very efficient code◦ Gives us very low-level control of the computer
Disadvantages◦ Writing large complex programs is very slow◦ Code not portable; the 80x86 assembly
instruction set is only valid on 80x86 CPUs For decades it was believed that “something
as complex as an operating system [has] to be written exclusively in assembly language"
Richard Khoury 4
C Language High-level language
◦ Portable, more efficient for program-writing◦ But minimalist: no runtime support, efficient
mapping from instructions to machine code, and allows low-level memory access
Originally developed in 1972 at AT&T Bell Labs as a “portable Assembly” language◦ So people began rewriting their old Assembly
programs in C
Richard Khoury 5
Unix History 1964: MIT, GE and Bell Labs team up to
build an OS called Multics◦ The last Multics system running was at the
Canadian Department of National Defence in Halifax, and shut down in 2000
1969: Bell Labs pulls out and start working on Unics
1970: Unix is up and running 1972: C language 1973: Unix is re-written in C language
◦ The first OS not written in Assembly◦ Since then, writing OS in C has become the norm
Richard Khoury 6
Merging C and Assembly We’ll start simply by moving our infinite
loop here int KernelMain ()
{for (;;);
return 0;}
Save as “main.c”
Richard Khoury 7
Merging C and Assembly We’ll need to change several things in
kernel.asm First, we need to call the main function from
the kernel, after displaying the welcome message
extern _KernelMaincall _KernelMain
◦ Replaces our infinite loop
Richard Khoury 8
Merging C and Assembly Before the jmp KernelCode, add the label start, which our linker will use as a starting point
global startstart:jmp KernelCode
Remove the org 0x100000 line, the linker will take care of that
And that’s it!◦ Our Assembly kernel now calls a C kernel◦ We can write our OS in C!
Richard Khoury 9
Display Functions Last week we created four Mode-7 display
functions in Assembly for our kernel◦ ClearScreen◦ DisplayString◦ DisplayChar◦ MoveCursor
We’ll rewrite them in C◦ Along with a few extra functions we’ll need
Richard Khoury 10
Writing an OS in C We are writing everything from scratch
◦ We can’t use pre-made standard libraries◦ Any definition, function, or included header file we
use, we have to make ourselves Data type hiding is key
◦ A major problem with our Assembly kernel is that it was dependent on 80x86 register names and sizes
◦ We want our C kernel to be hardware-independent◦ Therefore, we cannot use variable types that can
vary from system to system and compiler to compiler
Richard Khoury 11
Interface We’ll use an interface
◦ Define new names for each data type we’ll use that might cause compatibility issues
typedef int int32_t; ◦ Put them all in header files◦ Use our own names in the OS code◦ When we switch to a different system with
different data types, we’ll simply change the relevant header files
Richard Khoury 12
Interface To spare us from making hundreds of type
definitions, some header files are on the website◦ You should take a look in each of them later
_null.h: Defines the NULL constant size_t.h: Defines the unsigned type stdint.h: Defines various forms of integers ctype.h: ASCII-based character macros va_list.h: Variable-length argument list macros stdarg.h: Standard argument-list-handling
macros
Richard Khoury 13
Interface We’ll store these six header files away
somewhere, for neatness ◦ Somewhere our compiler will find them◦ Create an include subfolder called “include”◦ Later, we’ll specify to our C compiler to check that
folder
Richard Khoury 14
Display Functions We’re creating a set of functions to display
characters and strings in Mode 7◦ “mode7.c” and “mode7.h”
Begin with some useful global constants and variables#define VID_MEMORY 0xB8000#define COLS 80#define LINES 25static uint32_t _xPos=0, _yPos=0;static size_t _color=0;
Notice the use of our interfaces
Richard Khoury 15
DisplayChar Recall from Assembly: the char (without the
attributes) is just one byte, and unsigned◦ Again from stdint.h, we have:
typedef unsigned char uint8_t; The display char function needs to
◦ Skip the zero (empty) char◦ Change line at the special “change line” char◦ Change line after the last column◦ Write the char at the right place in memory,
followed by its attributes
Richard Khoury 16
DisplayCharvoid DisplayChar(uint8_t c){ Skip the zero (empty) char Change line at the special “change line” char Change line at the end of the column Write the char at the right place in memory, followed
by its attributes}
Richard Khoury 17
DisplayCharvoid DisplayChar(uint8_t c){ Skip the zero (empty) charif (c == 0)return;
Change line at the special “change line” char Change line at the end of the column Write the char at the right place in memory,
followed by its attributes}
Richard Khoury 18
DisplayCharvoid DisplayChar(uint8_t c){ Skip the zero (empty) char Change line at the special “change line” charif (c == '\n') {_yPos++;_xPos=0;if (_yPos >= LINES)ScrollUp();MoveCursor();return; }
Change line at the end of the column Write the char at the right place in memory,
followed by its attributes}
You can add other special characters this way, like \t and \b.
Richard Khoury 19
DisplayCharvoid DisplayChar(uint8_t c){ Skip the zero (empty) char Change line at the special “change line” char Change line at the end of the columnif (_xPos >= COLS) {_yPos++;_xPos=0;if (_yPos >= LINES)ScrollUp();}
Write the char at the right place in memory, followed by its attributes
}
Richard Khoury 20
DisplayCharvoid DisplayChar(uint8_t c){ Skip the zero (empty) char Change line at the special “change line” char Change line at the end of the column Write the char at the right place in memory, followed
by its attributesuint8_t* p = (uint8_t*)VID_MEMORY + _yPos * COLS * 2 + (_xPos++)*2;*p++ = c;*p =_color;MoveCursor();
}
Notice that, in addition to changing lines at the end of COLS, this function scrolls up at the end of LINES
We’ll need to write that functionvoid ScrollUp(){
◦ Loop through video memory, over the area corresponding to lines 0-23, copying the data from lines 1-24 over it
◦ Clear line 24◦ Update current position to last line
}
ScrollUp
Richard Khoury 21
Richard Khoury 22
DisplayString Like for the Assembly equivalent, this function will
break up a string into characters and call DisplayChar for each one
void DisplayString(uint8_t *str){if (!str)
return;
size_t i;for (i=0; i < strlen(str); i++)
DisplayChar(str[i]);}
Richard Khoury 23
DisplayString One difference is that the Assembly function
displayed chars in an endless loop until it hit the 0 char
In C, we evaluate the length of the string ◦ But we need to write our own strlen function
size_t strlen ( const uint8_t* str ) {size_t len=0;while (str[len++]);return len;
}
Richard Khoury 24
ClearScreen Unlike Assembly, this function allows users
to specify which colour to clear the screen to◦ Aside from that, the function works like in
Assembly
void ClearScreen (const size_t c) {
You have to write that function}
Richard Khoury 25
MoveCursor That one is a problem to write in C Recall: We had to access the CRTC registers
through the controller’s ports◦ Only a handful of commands in Assembly
mov al, 0x0f mov dx, 0x03D4 out dx, al
◦ High-level languages like C don’t give us this kind of control
Solution: call Assembly functions through C
Richard Khoury 26
MoveCursor In Assembly, we had four “out” commands
with different arguments in the registers So we’ll have one C function to call the
“out” command with given arguments In port.c and port.hvoid outport(uint16_t port, uint8_t data){ __asm__ __volatile__ ("out %1, %0" : : "dN" (port), "a" (data));
}
Richard Khoury 27
MoveCursor Then a function to call that one four times with the
right argumentsvoid MoveCursor(){ uint32_t cPos; cPos = _yPos * COLS + _xPos;
outport(0x3D4, 14); outport(0x3D5, cPos >> 8); outport(0x3D4, 15); outport(0x3D5, cPos);}
After we’ve rewritten all the old Assembly functions, it’s time for our first new function
This function will display a positive base-10 integer◦ That will be very useful as we build our OS
void DisplayInteger(uint32_t n) But how, since our DisplayChar can only
display individual characters (uint8_t)◦ We will need to convert the number digit by digit
DisplayInteger
Richard Khoury 28
void DisplayInteger(uint32_t n){ Handle the simple n=0 case Split the number right-to-left in individual
digits and store the ASCII value Display each digit in left-to-right order}
DisplayInteger
Richard Khoury 29
void DisplayInteger(uint32_t n){ Handle the simple n=0 caseif (n == 0)
{ DisplayChar('0'); return; } Split the number right-to-left in individual digits and
store the ASCII value Display each digit in left-to-right order}
DisplayInteger
Richard Khoury 30
void DisplayInteger(uint32_t n){ Handle the simple n=0 case Split the number right-to-left in individual digits and store the ASCII valueuint32_t acc = n;uint8_t c[32];
uint32_t i = 0; while (acc > 0) { c[i] = '0' + acc%10; acc /= 10; i++; } i--; Display each digit in left-to-right order}
DisplayInteger
Richard Khoury 31
void DisplayInteger(uint32_t n){ Handle the simple n=0 case Split the number right-to-left in individual digits and store the
ASCII value Display each digit in left-to-right order while (1) {DisplayChar(c[i]);if (i == 0) break;i--;
}}
DisplayInteger
Richard Khoury 32
Richard Khoury 33
Writing an OS in C Now we have our four Assembly display
functions in C, and more Don’t forget
◦ Write the function definitions in “mode7.h”extern void DisplayChar(uint8_t c);◦ Include the right header files◦ Include “mode7.h” in “main.c” so that we can
display stuff!
Richard Khoury 34
Lab Assignment Add a few more functions to get more display
options◦ ScrollUp
As explained in the slides, a function that copies lines 1-24 onto lines 0-23, then clears line 24 and update the position
◦ ClearScreen As explained in the slides, a function that clears the screen
to a background function passed in argument◦ SetColor
A function to change the character parameter variable◦ GotoXY
A function that moves the display & cursor to new (x,y) coordinates, so that the next character we write is at that position
And some interface functions that will be useful to display stuff◦ GetColor
Return the current value of the character parameter variable◦ GetWidth
Return the number of columns in the current display mode◦ GetHeight
Return the number of rows in the current display mode◦ GetXPos
Returns the cursor’s current X position◦ GetYPos
Returns the cursor’s current Y position
Lab Assignment
Richard Khoury 35
Richard Khoury 36
Lab Assignment Don’t forget to include the functions in this
presentation◦ DisplayChar◦ DisplayString◦ strlen◦ MoveCursor◦ DisplayInteger
Then update your main function to display a friendly, colourful welcome message for your OS somewhere on the screen
Richard Khoury 37
Kernel#include <mode7.h>int KernelMain () {//Clear the screen//Your welcome message here
SetColor(0x12);GotoXY(78,24);DisplayString("+-+-+-+-"); for (;;);return 0;}
Richard Khoury 38
Compiling and Linking What we’ll need An Assembly compiler
◦ We already have NASM A C compiler
◦ DJGPP: DOS port of GCC, the GNU Compiler A linker DOSBOX
◦ 32-bit DOS environment simulation, for GCC to work
Available on the course website
Richard Khoury 39
Compiling We will compile the Assembly and C files separately
into objects We use a different NASM option to compile the kernel
into an objectnasm -f aout -o kernel.o kernel.asm
GCC and LD are old 32-bit C compilers and linkers, won’t work in 64-bits Windows
We’ll run them in DOSBOX
Z:\>MOUNT C C:\Users\Richy\Desktop\OSLabZ:\>MOUNT D D:\Z:\> C:
Note: Dosbox uses 8.3 file name format, and does not allow spaces
Compiling
Richard Khoury 40
Richard Khoury 41
Compiling We compile the C file using DJGPP
set DJGPP=djgpp.env
gcc -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I./include -c -o main.o main.c◦ Compile only (no linking), without standard C libraries,
and include files are in the “include” subfolder Compile mode7.c and port.c separately, using the
same command as main.c
Richard Khoury 42
Linking We combine the object files into our kernel
using the linkerld -T link.ld -o KERNEL.BIN kernel.o main.o mode7.o port.o
Link using the details specified in link.ld◦ If you look at the file, you will find
ENTRY(start)◦ The start label I made you add
phys = 0x00100000;◦ The replacement for the ORG command we deleted
OUTPUT_FORMAT("binary")◦ Command to create a plain binary file
Richard Khoury 43
Testing Now we have the kernel.bin file that
combines both Assembly and C code We can copy it to our USB stick and test
We do have a lot of commands to type each time…◦ And we’ll add a lot more before the end of the
term◦ Tip: Make a .bat file with all the commands
written out, and just run that