multiboot.c

Go to the documentation of this file.
00001 /*
00002  * support for Multiboot payloads
00003  *
00004  * Copyright (C) 2008 Robert Millan
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, see <http://www.gnu.org/licenses/>.
00018  *
00019  */
00020 
00021 #include <cpu/x86/multiboot.h>
00022 #include <string.h>
00023 #include <device/resource.h>
00024 #include <console/console.h>
00025 
00026 typedef unsigned long long u64;
00027 
00028 static struct multiboot_mmap_entry *mb_mem;
00029 struct multiboot_info *mbi;
00030 
00031 static struct {
00032         u64 addr;
00033         u64 len;
00034 } reserved_mem[2];
00035 
00036 static void build_mb_mem_range_nooverlap(u64 addr, u64 len)
00037 {
00038         int i;
00039         for (i = 0; i < sizeof(reserved_mem) / sizeof(reserved_mem[0]); i++) {
00040                 /* free region fully contained in reserved region, abort */
00041                 if (addr >= reserved_mem[i].addr && addr + len <= reserved_mem[i].addr + reserved_mem[i].len)
00042                         return;
00043                 /* reserved region splits free region */
00044                 if (addr < reserved_mem[i].addr && addr + len > reserved_mem[i].addr + reserved_mem[i].len) {
00045                         build_mb_mem_range_nooverlap(addr, reserved_mem[i].addr - addr);
00046                         build_mb_mem_range_nooverlap(reserved_mem[i].addr + reserved_mem[i].len, (addr + len) - (reserved_mem[i].addr + reserved_mem[i].len));
00047                         return;
00048                 }
00049                 /* left overlap */
00050                 if (addr < reserved_mem[i].addr + reserved_mem[i].len && addr + len > reserved_mem[i].addr + reserved_mem[i].len) {
00051                         len += addr;
00052                         addr = reserved_mem[i].addr + reserved_mem[i].len;
00053                         len -= addr;
00054                         /* len += addr - old_addr */
00055                         continue;
00056                 }
00057                 /* right overlap */
00058                 if (addr < reserved_mem[i].addr && addr + len > reserved_mem[i].addr) {
00059                         len = reserved_mem[i].addr - addr;
00060                         continue;
00061                 }
00062                 /* none of the above, just add it */
00063         }
00064 
00065         mb_mem->addr = addr;
00066         mb_mem->len = len;
00067         mb_mem->type = 1;
00068         mb_mem->size = sizeof(*mb_mem) - sizeof(mb_mem->size);
00069         mb_mem++;
00070 }
00071 
00072 static void build_mb_mem_range(void *gp, struct device *dev, struct resource *res)
00073 {
00074         build_mb_mem_range_nooverlap(res->base, res->size);
00075 }
00076 
00077 #define ROUND(_r,_a) ((_r) + (((_a) - 1)) & ~((_a) - 1))
00078 
00079 unsigned long write_multiboot_info(
00080         unsigned long low_table_start, unsigned long low_table_end,
00081         unsigned long rom_table_start, unsigned long rom_table_end)
00082 {
00083         struct multiboot_info *mbi;
00084         int i;
00085 
00086         mbi = rom_table_end;
00087         memset(mbi, 0, sizeof(*mbi));
00088         rom_table_end += sizeof(*mbi);
00089 
00090         mbi->mmap_addr = (u32) rom_table_end;
00091         mb_mem = rom_table_end;
00092 
00093         /* reserved regions */
00094         reserved_mem[0].addr = low_table_start;
00095         reserved_mem[0].len = ROUND(low_table_end - low_table_start, 4096);
00096         reserved_mem[1].addr = rom_table_start;
00097         reserved_mem[1].len = ROUND(rom_table_end - rom_table_start, 4096);
00098 
00099         for (i = 0; i < sizeof(reserved_mem) / sizeof(reserved_mem[0]); i++) {
00100                 mb_mem->addr = reserved_mem[i].addr;
00101                 mb_mem->len = reserved_mem[i].len;
00102                 mb_mem->type = 2;
00103                 mb_mem->size = sizeof(*mb_mem) - sizeof(mb_mem->size);
00104                 mb_mem++;
00105         }
00106 
00107         /* free regions */
00108         search_global_resources( IORESOURCE_MEM | IORESOURCE_CACHEABLE,
00109                 IORESOURCE_MEM | IORESOURCE_CACHEABLE, build_mb_mem_range, NULL);
00110 
00111         mbi->mmap_length = ((u32) mb_mem) - mbi->mmap_addr;
00112         mbi->flags |= MB_INFO_MEM_MAP;
00113 
00114         printk_info("Multiboot Information structure has been written.\n");
00115 
00116         return mb_mem;
00117 }

Generated on Wed Jan 7 14:14:21 2009 for coreboot by  doxygen 1.5.5