/* Copyright (C) 2004 The SOS Team Copyright (C) 1999 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Include definitions of the multiboot standard */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Helper function to display each bits of a 32bits integer on the screen as dark or light carrets */ static void display_bits(unsigned char row, unsigned char col, unsigned char attribute, sos_ui32_t integer) { int i; /* Scan each bit of the integer, MSb first */ for (i = 31 ; i >= 0 ; i--) { /* Test if bit i of 'integer' is set */ int bit_i = (integer & (1 << i)); /* Ascii 219 => dark carret, Ascii 177 => light carret */ unsigned char ascii_code = bit_i?219:177; sos_x86_videomem_putchar(row, col++, attribute, ascii_code); } } /* Clock IRQ handler */ static void clk_it(int intid) { static sos_ui32_t clock_count = 0; display_bits(0, 48, SOS_X86_VIDEO_FG_LTGREEN | SOS_X86_VIDEO_BG_BLUE, clock_count); clock_count++; } /* Page fault exception handler */ static void pgflt_ex(int exid) { sos_bochs_printf("Got page fault\n"); sos_x86_videomem_printf(10, 30, SOS_X86_VIDEO_FG_LTRED | SOS_X86_VIDEO_BG_BLUE, "Got EXPECTED (?) Page fault ! But where ???"); for (;;) ; } static void test_paging(sos_vaddr_t sos_kernel_core_top_vaddr) { /* The (linear) address of the page holding the code we are currently executing */ sos_vaddr_t vpage_code = SOS_PAGE_ALIGN_INF(test_paging); /* The new physical page that will hold the code */ sos_paddr_t ppage_new; /* Where this page will be mapped temporarily in order to copy the code into it: right after the kernel code/data */ sos_vaddr_t vpage_tmp = sos_kernel_core_top_vaddr; unsigned i; /* Bind the page fault exception to one of our routines */ sos_exception_set_routine(SOS_EXCEPT_PAGE_FAULT, pgflt_ex); /* * Test 1: move the page where we execute the code elsewhere in * physical memory */ sos_x86_videomem_printf(4, 0, SOS_X86_VIDEO_FG_LTGREEN | SOS_X86_VIDEO_BG_BLUE, "Moving current code elsewhere in physical memory:"); /* Allocate a new physical page */ ppage_new = sos_physmem_ref_physpage_new(FALSE); if (! ppage_new) { /* STOP ! No memory left */ sos_x86_videomem_putstring(20, 0, SOS_X86_VIDEO_FG_LTRED | SOS_X86_VIDEO_BG_BLUE, "test_paging : Cannot allocate page"); return; } sos_x86_videomem_printf(5, 0, SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, "Hello from the address 0x%x in physical memory", sos_paging_get_paddr(vpage_code)); sos_x86_videomem_printf(6, 0, SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, "Transfer vpage 0x%x: ppage 0x%x -> 0x%x (tmp vpage 0x%x)", vpage_code, sos_paging_get_paddr(vpage_code), ppage_new, (unsigned)vpage_tmp); /* Map the page somewhere (right after the kernel mapping) in order to copy the code we are currently executing */ sos_paging_map(ppage_new, vpage_tmp, FALSE, SOS_VM_MAP_ATOMIC | SOS_VM_MAP_PROT_READ | SOS_VM_MAP_PROT_WRITE); /* Ok, the new page is referenced by the mapping, we can release our reference to it */ sos_physmem_unref_physpage(ppage_new); /* Copy the contents of the current page of code to this new page mapping */ memcpy((void*)vpage_tmp, (void*)vpage_code, SOS_PAGE_SIZE); /* Transfer the mapping of the current page of code to this new page */ sos_paging_map(ppage_new, vpage_code, FALSE, SOS_VM_MAP_ATOMIC | SOS_VM_MAP_PROT_READ | SOS_VM_MAP_PROT_WRITE); /* Ok, here we are: we have changed the physcal page that holds the code we are executing ;). However, this new page is mapped at 2 virtual addresses: - vpage_tmp - vpage_code We can safely unmap it from sos_kernel_core_top_vaddr, while still keeping the vpage_code mapping */ sos_paging_unmap(vpage_tmp); sos_x86_videomem_printf(7, 0, SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, "Hello from the address 0x%x in physical memory", sos_paging_get_paddr(vpage_code)); sos_x86_videomem_printf(9, 0, SOS_X86_VIDEO_FG_LTGREEN | SOS_X86_VIDEO_BG_BLUE, "Provoking a page fault:"); /* * Test 2: make sure the #PF handler works */ /* Scan part of the kernel up to a page fault. This page fault should occur on the first page unmapped after the kernel area, which is exactly the page we temporarily mapped/unmapped (vpage_tmp) above to move the kernel code we are executing */ for (i = vpage_code ; /* none */ ; i += SOS_PAGE_SIZE) { unsigned *pint = (unsigned *)SOS_PAGE_ALIGN_INF(i); sos_bochs_printf("Test vaddr 0x%x : val=", (unsigned)pint); sos_x86_videomem_printf(10, 0, SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, "Test vaddr 0x%x : val= ", (unsigned)pint); sos_bochs_printf("0x%x\n", *pint); sos_x86_videomem_printf(10, 30, SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, "0x%x ", *pint); } /* BAD ! Did not get the page fault... */ sos_x86_videomem_printf(20, 0, SOS_X86_VIDEO_FG_LTRED | SOS_X86_VIDEO_BG_BLUE, "We should have had a #PF at vaddr 0x%x !", vpage_tmp); } /* The C entry point of our operating system */ void sos_main(unsigned long magic, unsigned long addr) { unsigned i; sos_paddr_t sos_kernel_core_base_paddr, sos_kernel_core_top_paddr; /* Grub sends us a structure, called multiboot_info_t with a lot of precious informations about the system, see the multiboot documentation for more information. */ multiboot_info_t *mbi; mbi = (multiboot_info_t *) addr; /* Setup bochs and console, and clear the console */ sos_bochs_setup(); sos_x86_videomem_setup(); sos_x86_videomem_cls(SOS_X86_VIDEO_BG_BLUE); /* Greetings from SOS */ if (magic == MULTIBOOT_BOOTLOADER_MAGIC) /* Loaded with Grub */ sos_x86_videomem_printf(1, 0, SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, "Welcome From GRUB to %s%c RAM is %dMB (upper mem = 0x%x kB)", "SOS", ',', (unsigned)(mbi->mem_upper >> 10) + 1, (unsigned)mbi->mem_upper); else /* Not loaded with grub */ sos_x86_videomem_printf(1, 0, SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, "Welcome to SOS"); sos_bochs_putstring("Message in a bochs\n"); /* Setup CPU segmentation and IRQ subsystem */ sos_gdt_setup(); sos_idt_setup(); /* Setup SOS IRQs and exceptions subsystem */ sos_exceptions_setup(); sos_irq_setup(); /* Configure the timer so as to raise the IRQ0 at a 100Hz rate */ sos_i8254_set_frequency(100); /* We need a multiboot-compliant boot loader to get the size of the RAM */ if (magic != MULTIBOOT_BOOTLOADER_MAGIC) { sos_x86_videomem_putstring(20, 0, SOS_X86_VIDEO_FG_LTRED | SOS_X86_VIDEO_BG_BLUE | SOS_X86_VIDEO_FG_BLINKING, "I'm not loaded with Grub !"); /* STOP ! */ for (;;) continue; } /* Binding some HW interrupts and exceptions to software routines */ sos_irq_set_routine(SOS_IRQ_TIMER, clk_it); /* Enabling the HW interrupts here, this will make the timer HW interrupt call our clk_it handler */ asm volatile ("sti\n"); /* Multiboot says: "The value returned for upper memory is maximally the address of the first upper memory hole minus 1 megabyte.". It also adds: "It is not guaranteed to be this value." aka "YMMV" ;) */ sos_physmem_setup((mbi->mem_upper<<10) + (1<<20), & sos_kernel_core_base_paddr, & sos_kernel_core_top_paddr); /* * Switch to paged-memory mode */ /* Disabling interrupts should seem more correct, but it's not really necessary at this stage */ if (sos_paging_setup(sos_kernel_core_base_paddr, sos_kernel_core_top_paddr)) sos_bochs_printf("Could not setup paged memory mode\n"); sos_x86_videomem_printf(2, 0, SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, "Paged-memory mode is activated"); test_paging(sos_kernel_core_top_paddr); /* An operatig system never ends */ for (;;) continue; return; }