174e654c7c6d6e45bfdfceaca9c31662aaadfb276Feng Tang/*
274e654c7c6d6e45bfdfceaca9c31662aaadfb276Feng Tang * sfi.c - driver for parsing sfi mmap table and build e820 table
374e654c7c6d6e45bfdfceaca9c31662aaadfb276Feng Tang *
474e654c7c6d6e45bfdfceaca9c31662aaadfb276Feng Tang * Copyright (c) 2009, Intel Corporation.
574e654c7c6d6e45bfdfceaca9c31662aaadfb276Feng Tang *
674e654c7c6d6e45bfdfceaca9c31662aaadfb276Feng Tang * This program is free software; you can redistribute it and/or modify it
774e654c7c6d6e45bfdfceaca9c31662aaadfb276Feng Tang * under the terms and conditions of the GNU General Public License,
874e654c7c6d6e45bfdfceaca9c31662aaadfb276Feng Tang * version 2, as published by the Free Software Foundation.
974e654c7c6d6e45bfdfceaca9c31662aaadfb276Feng Tang *
1074e654c7c6d6e45bfdfceaca9c31662aaadfb276Feng Tang * This program is distributed in the hope it will be useful, but WITHOUT
1174e654c7c6d6e45bfdfceaca9c31662aaadfb276Feng Tang * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1274e654c7c6d6e45bfdfceaca9c31662aaadfb276Feng Tang * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
1374e654c7c6d6e45bfdfceaca9c31662aaadfb276Feng Tang * more details.
1474e654c7c6d6e45bfdfceaca9c31662aaadfb276Feng Tang *
1574e654c7c6d6e45bfdfceaca9c31662aaadfb276Feng Tang * You should have received a copy of the GNU General Public License along with
1674e654c7c6d6e45bfdfceaca9c31662aaadfb276Feng Tang * this program; if not, write to the Free Software Foundation, Inc.,
1774e654c7c6d6e45bfdfceaca9c31662aaadfb276Feng Tang * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
1874e654c7c6d6e45bfdfceaca9c31662aaadfb276Feng Tang */
1974e654c7c6d6e45bfdfceaca9c31662aaadfb276Feng Tang
207cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang#include "types.h"
217cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang#include "bootparam.h"
227cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang#include "bootstub.h"
238e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin#include "mb.h"
247cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang#include "sfi.h"
257cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang
267cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang#define SFI_BASE_ADDR		0x000E0000
277cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang#define SFI_LENGTH		0x00020000
287cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang
298e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kaluginstatic unsigned long sfi_search_mmap(unsigned long start, int len)
307cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang{
318e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	unsigned long i = 0;
328e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	char *pchar = (char *)start;
338e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin
348e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	for (i = 0; i < len; i++, pchar++) {
358e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin		if (pchar[0] == 'M'
368e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin			&& pchar[1] == 'M'
378e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin			&& pchar[2] == 'A'
388e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin			&& pchar[3] == 'P')
398e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin			return start + i;
408e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	}
418e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	return 0;
42afcd466aef22166c77f3f41414167972d44acd0bMark F. Brown}
43afcd466aef22166c77f3f41414167972d44acd0bMark F. Brown
448e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kaluginint sfi_add_e820_entry(struct boot_params *bp, memory_map_t *mb_mmap, u64 start, u64 size, int type)
45afcd466aef22166c77f3f41414167972d44acd0bMark F. Brown{
468e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin        struct e820entry * e820_entry;
478e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	memory_map_t	*mb_mmap_entry;
488e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	int	i;
498e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin
50978d75167a9d8f93641586f3969ce40a8d9177d7Michel Jauffres	if (!bp || !mb_mmap) {
51978d75167a9d8f93641586f3969ce40a8d9177d7Michel Jauffres		bs_printk("Bootstub: sfi_add_e820_entry failed\n");
52978d75167a9d8f93641586f3969ce40a8d9177d7Michel Jauffres		return -1;
53978d75167a9d8f93641586f3969ce40a8d9177d7Michel Jauffres	}
548e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin
558e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	for (i=0; i < bp->e820_entries; i++) {
568e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin		e820_entry = &(bp->e820_map[i]);
578e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin		mb_mmap_entry = &(mb_mmap[i]);
588e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin		if (e820_entry->addr == start) {
598e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin			/* Override size and type */
608e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin			e820_entry->size = size;
618e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin			e820_entry->type = type;
628e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin			mb_mmap_entry->length_low = size;
638e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin			mb_mmap_entry->length_high = 0;
648e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin			mb_mmap_entry->type = (type == E820_RAM)?1:0;
658e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin			return 0;
66afcd466aef22166c77f3f41414167972d44acd0bMark F. Brown		}
67afcd466aef22166c77f3f41414167972d44acd0bMark F. Brown	}
68afcd466aef22166c77f3f41414167972d44acd0bMark F. Brown
698e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	/* ASSERT: no duplicate start address found */
708e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	if (bp->e820_entries == E820MAX)
718e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin		return -1;
72afcd466aef22166c77f3f41414167972d44acd0bMark F. Brown
738e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	e820_entry = &(bp->e820_map[bp->e820_entries]);
748e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	mb_mmap_entry = &(mb_mmap[bp->e820_entries]);
75afcd466aef22166c77f3f41414167972d44acd0bMark F. Brown
768e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	e820_entry->addr = start;
778e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	e820_entry->size = size;
788e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	e820_entry->type = type;
79afcd466aef22166c77f3f41414167972d44acd0bMark F. Brown
808e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	mb_mmap_entry->size = 20;
818e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	mb_mmap_entry->base_addr_low = start;
828e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	mb_mmap_entry->base_addr_high = 0;
838e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	mb_mmap_entry->length_low = size;
848e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	mb_mmap_entry->length_high = 0;
858e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	mb_mmap_entry->type = (type == E820_RAM)?1:0;
868e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin
878e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	bp->e820_entries++;
88afcd466aef22166c77f3f41414167972d44acd0bMark F. Brown
897cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang	return 0;
907cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang}
917cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang
928e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kaluginvoid sfi_setup_mmap(struct boot_params *bp, memory_map_t *mb_mmap)
937cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang{
947cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang	struct sfi_table *sb;
957cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang	struct sfi_mem_entry *mentry;
967cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang	unsigned long long start, end, size;
978e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	int i, num, type;
987cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang
99978d75167a9d8f93641586f3969ce40a8d9177d7Michel Jauffres	if (!bp || !mb_mmap) {
100978d75167a9d8f93641586f3969ce40a8d9177d7Michel Jauffres		bs_printk("Bootstub: sfi_setup_mmap failed\n");
101978d75167a9d8f93641586f3969ce40a8d9177d7Michel Jauffres		return;
102978d75167a9d8f93641586f3969ce40a8d9177d7Michel Jauffres	}
103978d75167a9d8f93641586f3969ce40a8d9177d7Michel Jauffres
104978d75167a9d8f93641586f3969ce40a8d9177d7Michel Jauffres	bp->e820_entries = 0;
1057cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang
1067cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang	/* search for sfi mmap table */
1078e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	sb = (struct sfi_table *)sfi_search_mmap(SFI_BASE_ADDR, SFI_LENGTH);
1089fc3341bd5a5dcfeb4980b75eed2a743c604b638Jacob Pan	if (!sb) {
1098e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin		bs_printk("Bootstub: SFI MMAP table not found\n");
1107cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang		return;
1119fc3341bd5a5dcfeb4980b75eed2a743c604b638Jacob Pan	}
1128e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin	bs_printk("Bootstub: map SFI MMAP to e820 table\n");
1137cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang	num = SFI_GET_ENTRY_NUM(sb, sfi_mem_entry);
1147cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang	mentry = (struct sfi_mem_entry *)sb->pentry;
1157cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang
1167cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang	for (i = 0; i < num; i++) {
1177cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang		start = mentry->phy_start;
1187cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang		size = mentry->pages << 12;
1197cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang		end = start + size;
1207cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang
1217cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang		if (start > end)
1227cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang			continue;
1237cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang
1247cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang		/* translate SFI mmap type to E820 map type */
1257cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang		switch (mentry->type) {
1267cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang		case SFI_MEM_CONV:
1277cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang			type = E820_RAM;
1287cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang			break;
1297cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang		case SFI_MEM_UNUSABLE:
1307cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang		case SFI_RUNTIME_SERVICE_DATA:
1317cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang			mentry++;
1327cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang			continue;
1337cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang		default:
1347cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang			type = E820_RESERVED;
1357cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang		}
1367cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang
1378e8bf00a43ca772040ce02b2a8096d523171a8a4Evgeny Kalugin		if (sfi_add_e820_entry(bp, mb_mmap, start, size, type) != 0)
1387cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang			break;
1397cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang
1407cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang		mentry++;
1417cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang	}
1427cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang
1437cc52cde55aa85061da67d64212e036ac74d9e73Feng Tang}
144