Mercurial > hvf > hvf-old
view cp/mm/dat.c @ 618:535aec703236
cp: define a FIXME macro that leaves a sclp message
There are far too many fixmes in the code. Sadly, the compiler simply
discards them. This usually isn't an issue until one accidentally hits a
"weird" bug which just turns out to be an unhandled (but documented) case in
another part of the code. Using a macro instead of a comment will let the
compiler string-ify the text, and then at runtime use SCLP to print it out.
This will immediatelly point at problem areas. So, keep an eye on SCLP from
now on :)
Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Tue, 13 Dec 2011 22:20:50 -0500 |
parents | bf04161a8f5c |
children |
line wrap: on
line source
/* * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * * This file is released under the GPLv2. See the COPYING file for more * details. */ #include <page.h> #include <buddy.h> #include <dat.h> #include <mm.h> static void *alloc_table(int order) { struct page *p; p = alloc_pages(order, ZONE_NORMAL); BUG_ON(!p); memset(page_to_addr(p), 0xff, PAGE_SIZE << order); return page_to_addr(p); } /** * dat_insert_page - insert a virt->phy mapping into an address space * @as: address space to add the mapping to * @phy: physical address to add * @virt: virtual address to add */ int dat_insert_page(struct address_space *as, u64 phy, u64 virt) { struct dat_rte *region; struct dat_ste *segment; struct dat_pte *page; void *ptr; region = as->region_table; if (!region) { if (!as->segment_table) /* * Need to allocate the segment table * * max of 2048 * 8-byte entries = 16 kbytes */ as->segment_table = alloc_table(2); segment = as->segment_table; goto walk_segment; } if (DAT_RX(virt)) { FIXME("we don't support storage >2GB"); BUG(); } if (region->origin == 0xfffffffffffffUL) { /* * Need to allocate the segment table * * max of 2048 * 8-byte entries = 16 kbytes */ ptr = alloc_table(2); region->origin = ADDR_TO_RTE_ORIGIN((u64) ptr); region->tf = 0; region->i = 0; region->tt = DAT_RTE_TT_RTT; region->tl = 3; region->__reserved0 = 0; region->__reserved1 = 0; } segment = RTE_ORIGIN_TO_ADDR(region->origin); walk_segment: segment += DAT_SX(virt); if (segment->origin == 0x1fffffffffffffUL) { /* * Need to allocate the page table * * max of 256 * 8-byte entries = 2048 bytes */ ptr = alloc_table(0); segment->origin = ADDR_TO_STE_ORIGIN((u64) ptr); segment->p = 0; segment->i = 0; segment->c = 0; segment->tt = DAT_STE_TT_ST; segment->__reserved0 = 0; segment->__reserved1 = 0; segment->__reserved2 = 0; } page = STE_ORIGIN_TO_ADDR(segment->origin); page += DAT_PX(virt); page->pfra = phy >> PAGE_SHIFT; page->i = 0; page->p = 0; page->__zero0 = 0; page->__zero1 = 0; page->__reserved = 0; return 0; } void setup_dat(void) { /* nothing to do! */ } void load_as(struct address_space *as) { struct dat_td cr1; BUG_ON(!as->segment_table); /* * Load up the PASCE (cr1) */ memset(&cr1, 0, sizeof(struct dat_td)); cr1.origin = ((u64)as->segment_table) >> 12; cr1.dt = DAT_TD_DT_ST; cr1.tl = 3; asm volatile( " lctlg 1,1,%0\n" : /* output */ : /* input */ "m" (cr1) ); } /* memcpy that pays attention to page boundary crossing; *len contains the * number of bytes to copy on entry, and at return, the number of bytes * copied */ int __memcpy_tofrom_guest(u64 guest_addr, void *data, u64 *len, int from) { u8 *_data = data; u64 host_addr; u64 copy_len; u64 copied; int ret = 0; for(copied = 0; *len; ) { /* walk the page tables to find the real page frame */ ret = virt2phy_current(guest_addr, &host_addr); if (ret) break; /* copy this much this time around... until the end of the page, or * the while thing that's left */ copy_len = min(PAGE_SIZE - (host_addr & PAGE_MASK), *len); /* COPY! */ if (from) memcpy(_data + copied, (void*)host_addr, copy_len); else memcpy((void*)host_addr, _data + copied, copy_len); copied += copy_len; *len -= copy_len; } *len = copied; return ret; }