]>
Commit | Line | Data |
---|---|---|
06064872 TL |
1 | Ext.define('PVE.form.VMCPUFlagSelector', { |
2 | extend: 'Ext.grid.Panel', | |
3 | alias: 'widget.vmcpuflagselector', | |
4 | ||
5 | mixins: { | |
f6710aac | 6 | field: 'Ext.form.field.Field', |
06064872 TL |
7 | }, |
8 | ||
9 | disableSelection: true, | |
10 | columnLines: false, | |
11 | selectable: false, | |
12 | hideHeaders: true, | |
13 | ||
14 | scrollable: 'y', | |
15 | height: 200, | |
16 | ||
17 | unkownFlags: [], | |
18 | ||
19 | store: { | |
20 | type: 'store', | |
21 | fields: ['flag', { name: 'state', defaultValue: '=' }, 'desc'], | |
22 | data: [ | |
23 | // FIXME: let qemu-server host this and autogenerate or get from API call?? | |
24 | { flag: 'md-clear', desc: 'Required to let the guest OS know if MDS is mitigated correctly' }, | |
25 | { flag: 'pcid', desc: 'Meltdown fix cost reduction on Westmere, Sandy-, and IvyBridge Intel CPUs' }, | |
26 | { flag: 'spec-ctrl', desc: 'Allows improved Spectre mitigation with Intel CPUs' }, | |
27 | { flag: 'ssbd', desc: 'Protection for "Speculative Store Bypass" for Intel models' }, | |
28 | { flag: 'ibpb', desc: 'Allows improved Spectre mitigation with AMD CPUs' }, | |
29 | { flag: 'virt-ssbd', desc: 'Basis for "Speculative Store Bypass" protection for AMD models' }, | |
30 | { flag: 'amd-ssbd', desc: 'Improves Spectre mitigation performance with AMD CPUs, best used with "virt-ssbd"' }, | |
31 | { flag: 'amd-no-ssb', desc: 'Notifies guest OS that host is not vulnerable for Spectre on AMD CPUs' }, | |
b407310c SR |
32 | { flag: 'pdpe1gb', desc: 'Allow guest OS to use 1GB size pages, if host HW supports it' }, |
33 | { flag: 'hv-tlbflush', desc: 'Improve performance in overcommitted Windows guests. May lead to guest bluescreens on old CPUs.' }, | |
94961aff | 34 | { flag: 'hv-evmcs', desc: 'Improve performance for nested virtualization. Only supported on Intel CPUs.' }, |
f6710aac | 35 | { flag: 'aes', desc: 'Activate AES instruction set for HW acceleration.' }, |
06064872 TL |
36 | ], |
37 | listeners: { | |
38 | update: function() { | |
39 | this.commitChanges(); | |
f6710aac TL |
40 | }, |
41 | }, | |
06064872 TL |
42 | }, |
43 | ||
44 | getValue: function() { | |
45 | var me = this; | |
46 | var store = me.getStore(); | |
47 | var flags = ''; | |
48 | ||
49 | // ExtJS does not has a nice getAllRecords interface for stores :/ | |
50 | store.queryBy(Ext.returnTrue).each(function(rec) { | |
51 | var s = rec.get('state'); | |
52 | if (s && s !== '=') { | |
53 | var f = rec.get('flag'); | |
54 | if (flags === '') { | |
55 | flags = s + f; | |
56 | } else { | |
57 | flags += ';' + s + f; | |
58 | } | |
59 | } | |
60 | }); | |
61 | ||
62 | flags += me.unkownFlags.join(';'); | |
63 | ||
64 | return flags; | |
65 | }, | |
66 | ||
67 | setValue: function(value) { | |
68 | var me = this; | |
69 | var store = me.getStore(); | |
70 | ||
71 | me.value = value || ''; | |
72 | ||
73 | me.unkownFlags = []; | |
74 | ||
75 | me.getStore().queryBy(Ext.returnTrue).each(function(rec) { | |
76 | rec.set('state', '='); | |
77 | }); | |
78 | ||
79 | var flags = value ? value.split(';') : []; | |
80 | flags.forEach(function(flag) { | |
81 | var sign = flag.substr(0, 1); | |
82 | flag = flag.substr(1); | |
83 | ||
8267aa63 | 84 | var rec = store.findRecord('flag', flag, 0, false, true, true); |
06064872 TL |
85 | if (rec !== null) { |
86 | rec.set('state', sign); | |
87 | } else { | |
88 | me.unkownFlags.push(flag); | |
89 | } | |
90 | }); | |
91 | store.reload(); | |
92 | ||
93 | var res = me.mixins.field.setValue.call(me, value); | |
94 | ||
95 | return res; | |
96 | }, | |
97 | columns: [ | |
98 | { | |
99 | dataIndex: 'state', | |
100 | renderer: function(v) { | |
8058410f | 101 | switch (v) { |
06064872 TL |
102 | case '=': return 'Default'; |
103 | case '-': return 'Off'; | |
104 | case '+': return 'On'; | |
105 | default: return 'Unknown'; | |
106 | } | |
107 | }, | |
f6710aac | 108 | width: 65, |
06064872 TL |
109 | }, |
110 | { | |
111 | xtype: 'widgetcolumn', | |
112 | dataIndex: 'state', | |
113 | width: 95, | |
8058410f | 114 | onWidgetAttach: function(column, widget, record) { |
06064872 TL |
115 | var val = record.get('state') || '='; |
116 | widget.down('[inputValue=' + val + ']').setValue(true); | |
117 | // TODO: disable if selected CPU model and flag are incompatible | |
118 | }, | |
119 | widget: { | |
120 | xtype: 'radiogroup', | |
121 | hideLabel: true, | |
122 | layout: 'hbox', | |
123 | validateOnChange: false, | |
124 | value: '=', | |
125 | listeners: { | |
126 | change: function(f, value) { | |
127 | var v = Object.values(value)[0]; | |
128 | f.getWidgetRecord().set('state', v); | |
129 | ||
130 | var view = this.up('grid'); | |
131 | view.dirty = view.getValue() !== view.originalValue; | |
132 | view.checkDirty(); | |
133 | //view.checkChange(); | |
f6710aac | 134 | }, |
06064872 TL |
135 | }, |
136 | items: [ | |
137 | { | |
138 | boxLabel: '-', | |
139 | boxLabelAlign: 'before', | |
f6710aac | 140 | inputValue: '-', |
f871f785 | 141 | isFormField: false, |
06064872 TL |
142 | }, |
143 | { | |
144 | checked: true, | |
f6710aac | 145 | inputValue: '=', |
f871f785 | 146 | isFormField: false, |
06064872 TL |
147 | }, |
148 | { | |
149 | boxLabel: '+', | |
f6710aac | 150 | inputValue: '+', |
f871f785 | 151 | isFormField: false, |
f6710aac TL |
152 | }, |
153 | ], | |
154 | }, | |
06064872 TL |
155 | }, |
156 | { | |
157 | dataIndex: 'flag', | |
f6710aac | 158 | width: 100, |
06064872 TL |
159 | }, |
160 | { | |
161 | dataIndex: 'desc', | |
162 | cellWrap: true, | |
f6710aac TL |
163 | flex: 1, |
164 | }, | |
06064872 TL |
165 | ], |
166 | ||
167 | initComponent: function() { | |
168 | var me = this; | |
169 | ||
170 | // static class store, thus gets not recreated, so ensure defaults are set! | |
171 | me.getStore().data.forEach(function(v) { | |
172 | v.state = '='; | |
173 | }); | |
174 | ||
175 | me.value = me.originalValue = ''; | |
176 | ||
177 | me.callParent(arguments); | |
f6710aac | 178 | }, |
06064872 | 179 | }); |