loader: remove shouting from ORB's variable name
[hvf.git] / cp / mm / dat.c
blobec5b25e7bbeed2934429fcfbf91f309283fb16e1
1 /*
2 * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
4 * This file is released under the GPLv2. See the COPYING file for more
5 * details.
6 */
8 #include <page.h>
9 #include <buddy.h>
10 #include <dat.h>
11 #include <mm.h>
13 static void *alloc_table(int order)
15 struct page *p;
17 p = alloc_pages(order, ZONE_NORMAL);
18 BUG_ON(!p);
19 memset(page_to_addr(p), 0xff, PAGE_SIZE << order);
21 return page_to_addr(p);
24 /**
25 * dat_insert_page - insert a virt->phy mapping into an address space
26 * @as: address space to add the mapping to
27 * @phy: physical address to add
28 * @virt: virtual address to add
30 int dat_insert_page(struct address_space *as, u64 phy, u64 virt)
32 struct dat_rte *region;
33 struct dat_ste *segment;
34 struct dat_pte *page;
35 void *ptr;
37 region = as->region_table;
39 if (!region) {
40 if (!as->segment_table)
42 * Need to allocate the segment table
44 * max of 2048 * 8-byte entries = 16 kbytes
46 as->segment_table = alloc_table(2);
48 segment = as->segment_table;
50 goto walk_segment;
53 if (DAT_RX(virt)) {
54 FIXME("we don't support storage >2GB");
55 BUG();
58 if (region->origin == 0xfffffffffffffUL) {
60 * Need to allocate the segment table
62 * max of 2048 * 8-byte entries = 16 kbytes
64 ptr = alloc_table(2);
66 region->origin = ADDR_TO_RTE_ORIGIN((u64) ptr);
68 region->tf = 0;
69 region->i = 0;
70 region->tt = DAT_RTE_TT_RTT;
71 region->tl = 3;
72 region->__reserved0 = 0;
73 region->__reserved1 = 0;
76 segment = RTE_ORIGIN_TO_ADDR(region->origin);
78 walk_segment:
79 segment += DAT_SX(virt);
81 if (segment->origin == 0x1fffffffffffffUL) {
83 * Need to allocate the page table
85 * max of 256 * 8-byte entries = 2048 bytes
87 ptr = alloc_table(0);
89 segment->origin = ADDR_TO_STE_ORIGIN((u64) ptr);
90 segment->p = 0;
91 segment->i = 0;
92 segment->c = 0;
93 segment->tt = DAT_STE_TT_ST;
94 segment->__reserved0 = 0;
95 segment->__reserved1 = 0;
96 segment->__reserved2 = 0;
99 page = STE_ORIGIN_TO_ADDR(segment->origin);
100 page += DAT_PX(virt);
102 page->pfra = phy >> PAGE_SHIFT;
103 page->i = 0;
104 page->p = 0;
105 page->__zero0 = 0;
106 page->__zero1 = 0;
107 page->__reserved = 0;
109 return 0;
112 void setup_dat(void)
114 /* nothing to do! */
117 void load_as(struct address_space *as)
119 struct dat_td cr1;
121 BUG_ON(!as->segment_table);
124 * Load up the PASCE (cr1)
126 memset(&cr1, 0, sizeof(struct dat_td));
127 cr1.origin = ((u64)as->segment_table) >> 12;
128 cr1.dt = DAT_TD_DT_ST;
129 cr1.tl = 3;
131 asm volatile(
132 " lctlg 1,1,%0\n"
133 : /* output */
134 : /* input */
135 "m" (cr1)
139 /* memcpy that pays attention to page boundary crossing; *len contains the
140 * number of bytes to copy on entry, and at return, the number of bytes
141 * copied */
142 int __memcpy_tofrom_guest(u64 guest_addr, void *data, u64 *len, int from)
144 u8 *_data = data;
145 u64 host_addr;
146 u64 copy_len;
147 u64 copied;
148 int ret = 0;
150 for(copied = 0; *len; ) {
151 /* walk the page tables to find the real page frame */
152 ret = virt2phy_current(guest_addr, &host_addr);
153 if (ret)
154 break;
156 /* copy this much this time around... until the end of the page, or
157 * the while thing that's left
159 copy_len = min(PAGE_SIZE - (host_addr & PAGE_MASK), *len);
161 /* COPY! */
162 if (from)
163 memcpy(_data + copied, (void*)host_addr, copy_len);
164 else
165 memcpy((void*)host_addr, _data + copied, copy_len);
167 copied += copy_len;
168 *len -= copy_len;
171 *len = copied;
172 return ret;