Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / seabios / src / pmm.c
1 // Post memory manager (PMM) calls
2 //
3 // Copyright (C) 2009-2013  Kevin O'Connor <kevin@koconnor.net>
4 //
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
6
7 #include "biosvar.h" // FUNC16
8 #include "config.h" // CONFIG_*
9 #include "malloc.h" // _malloc
10 #include "output.h" // dprintf
11 #include "std/pmm.h" // PMM_SIGNATURE
12 #include "string.h" // checksum
13 #include "util.h" // pmm_init
14 #include "x86.h" // __ffs
15
16 extern struct pmmheader PMMHEADER;
17
18 #if CONFIG_PMM
19 struct pmmheader PMMHEADER __aligned(16) VARFSEG = {
20     .signature = PMM_SIGNATURE,
21     .version = 0x01,
22     .length = sizeof(PMMHEADER),
23 };
24 #endif
25
26 // PMM - allocate
27 static u32
28 handle_pmm00(u16 *args)
29 {
30     u32 length = *(u32*)&args[1], handle = *(u32*)&args[3];
31     u16 flags = args[5];
32     dprintf(3, "pmm00: length=%x handle=%x flags=%x\n"
33             , length, handle, flags);
34     struct zone_s *lowzone = &ZoneTmpLow, *highzone = &ZoneTmpHigh;
35     if (flags & 8) {
36         // Permanent memory request.
37         lowzone = &ZoneLow;
38         highzone = &ZoneHigh;
39     }
40     if (!length) {
41         // Memory size request
42         switch (flags & 3) {
43         default:
44         case 0:
45             return 0;
46         case 1:
47             return malloc_getspace(lowzone);
48         case 2:
49             return malloc_getspace(highzone);
50         case 3: {
51             u32 spacelow = malloc_getspace(lowzone);
52             u32 spacehigh = malloc_getspace(highzone);
53             if (spacelow > spacehigh)
54                 return spacelow;
55             return spacehigh;
56         }
57         }
58     }
59     u32 size = length * 16;
60     if ((s32)size <= 0)
61         return 0;
62     u32 align = MALLOC_MIN_ALIGN;
63     if (flags & 4) {
64         align = 1<<__ffs(size);
65         if (align < MALLOC_MIN_ALIGN)
66             align = MALLOC_MIN_ALIGN;
67     }
68     void *data;
69     switch (flags & 3) {
70     default:
71     case 0:
72         return 0;
73     case 1:
74         data = _malloc(lowzone, size, align);
75         break;
76     case 2:
77         data = _malloc(highzone, size, align);
78         break;
79     case 3: {
80         data = _malloc(lowzone, size, align);
81         if (!data)
82             data = _malloc(highzone, size, align);
83     }
84     }
85     if (data && handle != MALLOC_DEFAULT_HANDLE)
86         malloc_sethandle(data, handle);
87     return (u32)data;
88 }
89
90 // PMM - find
91 static u32
92 handle_pmm01(u16 *args)
93 {
94     u32 handle = *(u32*)&args[1];
95     dprintf(3, "pmm01: handle=%x\n", handle);
96     if (handle == MALLOC_DEFAULT_HANDLE)
97         return 0;
98     return (u32)malloc_findhandle(handle);
99 }
100
101 // PMM - deallocate
102 static u32
103 handle_pmm02(u16 *args)
104 {
105     u32 buffer = *(u32*)&args[1];
106     dprintf(3, "pmm02: buffer=%x\n", buffer);
107     int ret = _free((void*)buffer);
108     if (ret)
109         // Error
110         return 1;
111     return 0;
112 }
113
114 static u32
115 handle_pmmXX(u16 *args)
116 {
117     return PMM_FUNCTION_NOT_SUPPORTED;
118 }
119
120 u32 VISIBLE32INIT
121 handle_pmm(u16 *args)
122 {
123     ASSERT32FLAT();
124     if (! CONFIG_PMM)
125         return PMM_FUNCTION_NOT_SUPPORTED;
126
127     u16 arg1 = args[0];
128     dprintf(DEBUG_HDL_pmm, "pmm call arg1=%x\n", arg1);
129
130     u32 ret;
131     switch (arg1) {
132     case 0x00: ret = handle_pmm00(args); break;
133     case 0x01: ret = handle_pmm01(args); break;
134     case 0x02: ret = handle_pmm02(args); break;
135     default:   ret = handle_pmmXX(args); break;
136     }
137
138     return ret;
139 }
140
141 void
142 pmm_init(void)
143 {
144     if (! CONFIG_PMM)
145         return;
146
147     dprintf(3, "init PMM\n");
148
149     PMMHEADER.entry = FUNC16(entry_pmm);
150     PMMHEADER.checksum -= checksum(&PMMHEADER, sizeof(PMMHEADER));
151 }
152
153 void
154 pmm_prepboot(void)
155 {
156     if (! CONFIG_PMM)
157         return;
158
159     dprintf(3, "finalize PMM\n");
160
161     PMMHEADER.signature = 0;
162     PMMHEADER.entry.segoff = 0;
163 }