You may have read my previous post about writing a Hello World operating system. Although I did post this on April 1st it wasn’t actually a prank, and it does actually work.
I decided to improve the code. With the following replacement for main.c we can print “Hello World!” on the screen in a more developer friendly way.
char * vidmem = (char*)0xB8000; int pos = 0; void putc(char ch){ vidmem[pos++] = ch; vidmem[pos++] = 0x7; } void puts(char* s){ int c; for(c = 0; s[c] != ''; c++) putc(s[c]); } int main(){ puts("Hello World!"); }
Now this is all very good, but suppose you need to check that some number in your os is some value that you expected, we are going to have to write a function to convert the number into an ascii representation before displaying it on the screen, we can’t use the itoa() function of the standard c library, because we didn’t compile it into our OS. We need to instead roll our own itoa function.
int strsize(char* str){ int i; for(i = 0;str[i]!='';i++); return i; } char* strrev(char* str){ char* tmp; int i = strsize(str) - 1; int j = 0; while(i>=0){ tmp[j] = str[i]; i--; j++; } tmp[j] = ''; return tmp; } char* toDigit(int n){ char digits[10] = "0123456789"; char* str; int i = 0; while(n/10){ str[i] = digits[n%10]; i++; n/=10; } str[i] = digits[n%10]; i++; str[i] = ''; return strrev(str); }
This initial attempt might have worked, however its riddled with errors, which I have since learned about. For example returning a pointer to a stack variable, is probably not a good idea!
When I originally wrote this I hadn’t seen the Kerrigan an Ritchie implementation thier implementation is much better has more features, and less bugs. After re-writing the code my final version of main.c was as follows
char * vidmem = (char*)0xB8000; int pos = 0; int strlen(const char * str) { const char *s; for (s = str; *s; ++s); return(s - str); } void strrev(char s[]) { int i, j; char c; for (i = 0, j = strlen(s)-1; i<j; i++, j--) { c = s[i]; s[i] = s[j]; s[j] = c; } } void itoa(int n, char s[]) { int i, sign; if ((sign = n) 0); if (sign < 0) s[i++] = '-'; s[i] = ''; strrev(s); } void putch(char ch){ vidmem[pos++] = ch; vidmem[pos++] = 0x7; } void clrscr() { int i; for(i=0;i<80*25;i++) putch(' '); pos=0; } void putstr(char* str){ const char *c; for (c = str; *c; ++c) putch(*c); } int main() { char str[10]; int i = 100; clrscr(); putstr("Hello World! "); itoa(i,str); putstr(str); }
how would you boot to this from grub? don’t you need an boot image for menu.lst?
GRUB can load the kernel directly, either in ELF or a.out format. Have a read of Part 1 to see how to create an ELF executable that can be booted by grub.