#include #include "list.h" typedef unsigned long long u64; #define PHYS_SECTION_UNDEF 0 #define PHYS_SECTION_DEF ~0ul #define PHYS_SECTION_RAM 1<<0 #define PHYS_SECTION_RAM_DISABLED 1<<1 #define PHYS_SECTION_HOLE 1<<2 #define PHYS_SECTION_ATTR_END 3 /* these would be in per-arch headers */ #define PHYS_SECTION_PCI_SPACE 1<<(PHYS_SECTION_ATTR_END+0) #define PHYS_SECTION_RESERVED 1<<(PHYS_SECTION_ATTR_END+1) #define PHYS_SECTION_BAR 1<<(PHYS_SECTION_ATTR_END+2) /* this would copy any arch-private fields */ #define section_attr_copy_arch(...) do {} while(0); struct phys_layout_section_arch { u64 numa_proximity; }; /* end of per-arch headers */ struct phys_layout_section { u64 start_phys_addr; u64 end_phys_addr; unsigned long attributes; struct phys_layout_section_arch arch; struct list_head list; }; #define MAX_SECTIONS 128 static struct phys_layout_section sections[MAX_SECTIONS]; int sections_used = 0; void section_attr_copy(struct phys_layout_section *dst, struct phys_layout_section *src) { dst->arch = src->arch; section_attr_copy_arch(dst, src); } void add_next_section(struct phys_layout_section *new, struct phys_layout_section *head) { list_add(&new->list, &head->list); } void add_prev_section(struct phys_layout_section *new, struct phys_layout_section *head) { list_add_tail(&new->list, &head->list); } struct phys_layout_section *alloc_phys_section() { return §ions[sections_used++]; } int section_contains(struct phys_layout_section * section, u64 addr) { return (addr >= section->start_phys_addr && addr < section->end_phys_addr); } LIST_HEAD(section_list); void print_section(int i, struct phys_layout_section *section) { printf("section %d: %016Lx-%016Lx %08lx\n", i++, section->start_phys_addr, section->end_phys_addr, section->attributes); } void print_sections(void) { struct list_head *entry = NULL; int i=0; list_for_each(entry, §ion_list) { struct phys_layout_section *section; section = list_entry(entry, struct phys_layout_section, list); print_section(i++, section); } printf("--------------------------------------------\n"); } struct phys_layout_section *add_phys_section(u64 new_start_addr, u64 new_end_addr, unsigned long attributes) { struct list_head *entry = NULL; struct phys_layout_section *section = NULL; struct phys_layout_section *new_section; struct phys_layout_section *split_section; int i=0; u64 old_end_addr; list_for_each(entry, §ion_list) { section = list_entry(entry, struct phys_layout_section, list); if (!section_contains(section, new_start_addr)) continue; /* same attributes, just extend it */ if (section->attributes == attributes) { if (section->end_phys_addr < new_end_addr) section->end_phys_addr = new_end_addr; break; } /* new section needed */ new_section = alloc_phys_section(); new_section->start_phys_addr = new_start_addr; new_section->end_phys_addr = new_end_addr; new_section->attributes = attributes; /* This started in the same place as the old one */ if (section->start_phys_addr == new_start_addr) { /* shift start of the old one up */ section->start_phys_addr = new_end_addr; add_prev_section(new_section, section); break; } /* * New section started in the middle of the old one. * Truncate the old one, so that it ends at the start * of the new one. */ old_end_addr = section->end_phys_addr; section->end_phys_addr = new_start_addr; add_next_section(new_section, section); /* New section covered the rest of the old section */ if (old_end_addr == new_end_addr) break; /* * The new section was spanned by the old one, and the old * one had to be split. Another section is needed for the * remainder of the old area. Extend the "new_section", so * that the split section can truncate it in the recursion. * * This will only recurse once, and terminate at the break * immediately above. */ new_section->end_phys_addr = old_end_addr; split_section = add_phys_section(new_end_addr, old_end_addr, section->attributes); section_attr_copy(split_section, section); break; } return new_section; } u64 get_total_attr_size(unsigned long attr) { struct list_head *entry = NULL; u64 result = 0; list_for_each(entry, §ion_list) { struct phys_layout_section *section; section = list_entry(entry, struct phys_layout_section, list); if (section->attributes & attr) result += section->end_phys_addr - section->start_phys_addr; } return result; } int main() { int i; sections_used = 1; sections[0].end_phys_addr = -1; sections[0].attributes = PHYS_SECTION_UNDEF; INIT_LIST_HEAD(§ions[0].list); list_add(§ions[0].list, §ion_list); print_sections(); add_phys_section(0x0000, 0x1000, PHYS_SECTION_HOLE); add_phys_section(0x1000, 0x2000, PHYS_SECTION_RAM); add_phys_section(0x2000, 0x9000, PHYS_SECTION_HOLE); add_phys_section(0x3000, 0x6000, PHYS_SECTION_RAM); /* disable some ram for mem= */ add_phys_section(0x5000, 0x6000, PHYS_SECTION_RAM_DISABLED); print_sections(); printf("disabled RAM size: %Ld\n", get_total_attr_size(PHYS_SECTION_RAM_DISABLED)); printf(" RAM size: %Ld\n", get_total_attr_size(PHYS_SECTION_RAM)); printf(" hole size: %Ld\n", get_total_attr_size(PHYS_SECTION_HOLE)); printf(" any size: %Ld\n", get_total_attr_size(PHYS_SECTION_DEF)); }