1/* kernel.c - the C part of the kernel */
2/* Copyright (C) 1999  Free Software Foundation, Inc.
3
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation; either version 2 of the License, or
7   (at your option) any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13
14   You should have received a copy of the GNU General Public License
15   along with this program; if not, write to the Free Software
16   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
17
18#include <multiboot.h>
19
20/* Macros.  */
21
22/* Check if the bit BIT in FLAGS is set.  */
23#define CHECK_FLAG(flags,bit)	((flags) & (1 << (bit)))
24
25/* Some screen stuff.  */
26/* The number of columns.  */
27#define COLUMNS			80
28/* The number of lines.  */
29#define LINES			24
30/* The attribute of an character.  */
31#define ATTRIBUTE		7
32/* The video memory address.  */
33#define VIDEO			0xB8000
34
35/* Variables.  */
36/* Save the X position.  */
37static int xpos;
38/* Save the Y position.  */
39static int ypos;
40/* Point to the video memory.  */
41static volatile unsigned char *video;
42
43/* Forward declarations.  */
44void cmain (unsigned long magic, unsigned long addr);
45static void cls (void);
46static void itoa (char *buf, int base, int d);
47static void putchar (int c);
48void printf (const char *format, ...);
49
50/* Check if MAGIC is valid and print the Multiboot information structure
51   pointed by ADDR.  */
52void
53cmain (unsigned long magic, unsigned long addr)
54{
55  multiboot_info_t *mbi;
56
57  /* Clear the screen.  */
58  cls ();
59
60  /* Am I booted by a Multiboot-compliant boot loader?  */
61  if (magic != MULTIBOOT_BOOTLOADER_MAGIC)
62    {
63      printf ("Invalid magic number: 0x%x\n", (unsigned) magic);
64      return;
65    }
66
67  /* Set MBI to the address of the Multiboot information structure.  */
68  mbi = (multiboot_info_t *) addr;
69
70  /* Print out the flags.  */
71  printf ("flags = 0x%x\n", (unsigned) mbi->flags);
72
73  /* Are mem_* valid?  */
74  if (CHECK_FLAG (mbi->flags, 0))
75    printf ("mem_lower = %uKB, mem_upper = %uKB\n",
76	    (unsigned) mbi->mem_lower, (unsigned) mbi->mem_upper);
77
78  /* Is boot_device valid?  */
79  if (CHECK_FLAG (mbi->flags, 1))
80    printf ("boot_device = 0x%x\n", (unsigned) mbi->boot_device);
81
82  /* Is the command line passed?  */
83  if (CHECK_FLAG (mbi->flags, 2))
84    printf ("cmdline = %s\n", (char *) mbi->cmdline);
85
86  /* Are mods_* valid?  */
87  if (CHECK_FLAG (mbi->flags, 3))
88    {
89      module_t *mod;
90      int i;
91
92      printf ("mods_count = %d, mods_addr = 0x%x\n",
93	      (int) mbi->mods_count, (int) mbi->mods_addr);
94      for (i = 0, mod = (module_t *) mbi->mods_addr;
95	   i < mbi->mods_count;
96	   i++, mod++)
97	printf (" mod_start = 0x%x, mod_end = 0x%x, string = %s\n",
98		(unsigned) mod->mod_start,
99		(unsigned) mod->mod_end,
100		(char *) mod->string);
101    }
102
103  /* Bits 4 and 5 are mutually exclusive!  */
104  if (CHECK_FLAG (mbi->flags, 4) && CHECK_FLAG (mbi->flags, 5))
105    {
106      printf ("Both bits 4 and 5 are set.\n");
107      return;
108    }
109
110  /* Is the symbol table of a.out valid?  */
111  if (CHECK_FLAG (mbi->flags, 4))
112    {
113      aout_symbol_table_t *aout_sym = &(mbi->u.aout_sym);
114
115      printf ("aout_symbol_table: tabsize = 0x%0x, "
116	      "strsize = 0x%x, addr = 0x%x\n",
117	      (unsigned) aout_sym->tabsize,
118	      (unsigned) aout_sym->strsize,
119	      (unsigned) aout_sym->addr);
120    }
121
122  /* Is the section header table of ELF valid?  */
123  if (CHECK_FLAG (mbi->flags, 5))
124    {
125      elf_section_header_table_t *elf_sec = &(mbi->u.elf_sec);
126
127      printf ("elf_sec: num = %u, size = 0x%x,"
128	      " addr = 0x%x, shndx = 0x%x\n",
129	      (unsigned) elf_sec->num, (unsigned) elf_sec->size,
130	      (unsigned) elf_sec->addr, (unsigned) elf_sec->shndx);
131    }
132
133  /* Are mmap_* valid?  */
134  if (CHECK_FLAG (mbi->flags, 6))
135    {
136      memory_map_t *mmap;
137
138      printf ("mmap_addr = 0x%x, mmap_length = 0x%x\n",
139	      (unsigned) mbi->mmap_addr, (unsigned) mbi->mmap_length);
140      for (mmap = (memory_map_t *) mbi->mmap_addr;
141	   (unsigned long) mmap < mbi->mmap_addr + mbi->mmap_length;
142	   mmap = (memory_map_t *) ((unsigned long) mmap
143				    + mmap->size + sizeof (mmap->size)))
144	printf (" size = 0x%x, base_addr = 0x%x%x,"
145		" length = 0x%x%x, type = 0x%x\n",
146		(unsigned) mmap->size,
147		(unsigned) mmap->base_addr_high,
148		(unsigned) mmap->base_addr_low,
149		(unsigned) mmap->length_high,
150		(unsigned) mmap->length_low,
151		(unsigned) mmap->type);
152    }
153}
154
155/* Clear the screen and initialize VIDEO, XPOS and YPOS.  */
156static void
157cls (void)
158{
159  int i;
160
161  video = (unsigned char *) VIDEO;
162
163  for (i = 0; i < COLUMNS * LINES * 2; i++)
164    *(video + i) = 0;
165
166  xpos = 0;
167  ypos = 0;
168}
169
170/* Convert the integer D to a string and save the string in BUF. If
171   BASE is equal to 'd', interpret that D is decimal, and if BASE is
172   equal to 'x', interpret that D is hexadecimal.  */
173static void
174itoa (char *buf, int base, int d)
175{
176  char *p = buf;
177  char *p1, *p2;
178  unsigned long ud = d;
179  int divisor = 10;
180
181  /* If %d is specified and D is minus, put `-' in the head.  */
182  if (base == 'd' && d < 0)
183    {
184      *p++ = '-';
185      buf++;
186      ud = -d;
187    }
188  else if (base == 'x')
189    divisor = 16;
190
191  /* Divide UD by DIVISOR until UD == 0.  */
192  do
193    {
194      int remainder = ud % divisor;
195
196      *p++ = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10;
197    }
198  while (ud /= divisor);
199
200  /* Terminate BUF.  */
201  *p = 0;
202
203  /* Reverse BUF.  */
204  p1 = buf;
205  p2 = p - 1;
206  while (p1 < p2)
207    {
208      char tmp = *p1;
209      *p1 = *p2;
210      *p2 = tmp;
211      p1++;
212      p2--;
213    }
214}
215
216/* Put the character C on the screen.  */
217static void
218putchar (int c)
219{
220  if (c == '\n' || c == '\r')
221    {
222    newline:
223      xpos = 0;
224      ypos++;
225      if (ypos >= LINES)
226	ypos = 0;
227      return;
228    }
229
230  *(video + (xpos + ypos * COLUMNS) * 2) = c & 0xFF;
231  *(video + (xpos + ypos * COLUMNS) * 2 + 1) = ATTRIBUTE;
232
233  xpos++;
234  if (xpos >= COLUMNS)
235    goto newline;
236}
237
238/* Format a string and print it on the screen, just like the libc
239   function printf.  */
240void
241printf (const char *format, ...)
242{
243  char **arg = (char **) &format;
244  int c;
245  char buf[20];
246
247  arg++;
248
249  while ((c = *format++) != 0)
250    {
251      if (c != '%')
252	putchar (c);
253      else
254	{
255	  char *p;
256
257	  c = *format++;
258	  switch (c)
259	    {
260	    case 'd':
261	    case 'u':
262	    case 'x':
263	      itoa (buf, c, *((int *) arg++));
264	      p = buf;
265	      goto string;
266	      break;
267
268	    case 's':
269	      p = *arg++;
270	      if (! p)
271		p = "(null)";
272
273	    string:
274	      while (*p)
275		putchar (*p++);
276	      break;
277
278	    default:
279	      putchar (*((int *) arg++));
280	      break;
281	    }
282	}
283    }
284}
285