Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
xcap
xcap-capability-linux
Commits
df841332
Commit
df841332
authored
Nov 27, 2013
by
Weibin Sun
Committed by
Vikram Narayanan
Oct 25, 2016
Browse files
fix compilation, keep debugging
parent
ffca5efc
Changes
2
Hide whitespace changes
Inline
Side-by-side
arch/x86/lcd/lcd_defs.h
View file @
df841332
#ifndef LCD_LCD_H
#define LCD_LCD_H
#ifndef LCD_LCD_
DEFS_
H
#define LCD_LCD_
DEFS_
H
#include <linux/bitmap.h>
#if !defined(VMX_EPT_AD_BIT)
#define VMX_EPT_AD_BIT (1ull << 21)
#define VMX_EPT_AD_ENABLE_BIT (1ull << 6)
#endif
#ifndef VMX_EPT_EXTENT_INDIVIDUAL_BIT
#define VMX_EPT_EXTENT_INDIVIDUAL_BIT (1ull << 24)
#endif
#ifndef X86_CR4_PCIDE
#define X86_CR4_PCIDE0x00020000
/* enable PCID support */
#endif
#ifndef SECONDARY_EXEC_ENABLE_INVPCID
#define SECONDARY_EXEC_ENABLE_INVPCID0x00001000
#endif
#ifndef SEG_TYPE_DATA
#define SEG_TYPE_DATA (0 << 3)
#endif
#ifndef SEG_TYPE_READ_WRITE
#define SEG_TYPE_READ_WRITE (1 << 1)
#endif
#ifndef SEG_TYPE_CODE
#define SEG_TYPE_CODE (1 << 3)
#endif
#ifndef SEG_TYPE_EXEC_READ
#define SEG_TYPE_EXEC_READ (1 << 1)
#endif
#ifndef SEG_TYPE_TSS
#define SEG_TYPE_TSS ((1 << 3) | (1 << 0))
#endif
#ifndef SEG_OP_SIZE_32BIT
#define SEG_OP_SIZE_32BIT (1 << 0)
#endif
#ifndef SEG_GRANULARITY_4KB
#define SEG_GRANULARITY_4KB (1 << 0)
#endif
#ifndef DESC_TYPE_CODE_DATA
#define DESC_TYPE_CODE_DATA (1 << 0)
#endif
/* Memory management */
#define NR_PT_PAGES (1 << 12)
/* #pages for page table */
...
...
@@ -18,6 +67,8 @@
#define VMX_EPT_FAULT_INS 0x04
typedef
unsigned
long
epte_t
;
typedef
unsigned
long
gpa_t
;
typedef
unsigned
long
gva_t
;
#define __EPTE_READ 0x01
#define __EPTE_WRITE 0x02
...
...
@@ -151,6 +202,8 @@ struct lcd_tss_struct {
#define LCD_STACK_ADDR (0x1ULL << 31)
#define LCD_STACK_SIZE (PAGE_SIZE * 4)
#define LCD_CODE_ADDR (0x1ULL << 32)
#define LCD_ISR_ADDR LCD_STACK_ADDR
#endif
arch/x86/lcd/lcd_main.c
View file @
df841332
...
...
@@ -4,22 +4,30 @@
* Based on KVM and Dune.
*
*/
#include "lcd.h"
#include "lcd_defs.h"
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/slab.h>
#include <linux/tboot.h>
#include <asm/vmx.h>
#include <asm/processor.h>
#include <asm/desc.h>
#include <asm/virtext.h>
#include "lcd.h"
#include "lcd_defs.h"
MODULE_AUTHOR
(
"Weibin Sun"
);
MODULE_LICENSE
(
"GPL"
);
struct
vmx_capability
vmx_capability
;
static
atomic_t
vmx_enable_failed
;
static
DECLARE_BITMAP
(
vmx_vpid_bitmap
,
VMX_NR_VPIDS
);
static
DEFINE_SPINLOCK
(
vmx_vpid_lock
);
...
...
@@ -28,7 +36,9 @@ static DEFINE_PER_CPU(struct desc_ptr, host_gdt);
static
DEFINE_PER_CPU
(
int
,
vmx_enabled
);
static
DEFINE_PER_CPU
(
struct
vmx_vcpu
*
,
local_vcpu
);
static
struct
vmcs_config
vmcs_config
;
static
unsigned
long
*
msr_bitmap
;
struct
vmcs_config
vmcs_config
;
/* CPU Features and Ops */
...
...
@@ -146,7 +156,7 @@ static inline u16 vmx_read_ldt(void) {
return
ldt
;
}
static
__init
bool
allow_1_setting
(
u32
msr
,
u32
ctl
)
{
static
bool
allow_1_setting
(
u32
msr
,
u32
ctl
)
{
u32
vmx_msr_low
,
vmx_msr_high
;
rdmsr
(
msr
,
vmx_msr_low
,
vmx_msr_high
);
...
...
@@ -254,6 +264,10 @@ static inline int epte_present(epte_t epte) {
return
(
epte
&
__EPTE_FULL
)
>
0
;
}
static
inline
int
epte_big
(
epte_t
epte
)
{
return
(
epte
&
__EPTE_SZ
)
>
0
;
}
static
void
free_ept_page
(
epte_t
epte
)
{
struct
page
*
page
=
pfn_to_page
(
epte_addr
(
epte
)
>>
PAGE_SHIFT
);
...
...
@@ -272,26 +286,6 @@ static int clear_epte(epte_t *epte) {
return
1
;
}
static
int
clear_l1_epte
(
epte_t
*
epte
)
{
int
i
;
epte_t
*
pte
=
(
epte_t
*
)
epte_page_vaddr
(
*
epte
);
if
(
*
epte
==
__EPTE_NONE
)
return
0
;
for
(
i
=
0
;
i
<
PTRS_PER_PTE
;
i
++
)
{
if
(
!
epte_present
(
pte
[
i
]))
continue
;
free_ept_page
(
pte
[
i
]);
}
free_page
((
uintptr_t
)
pte
);
*
epte
=
__EPTE_NONE
;
return
1
;
}
static
int
ept_lookup_gpa
(
struct
vmx_vcpu
*
vcpu
,
void
*
gpa
,
int
create
,
...
...
@@ -359,11 +353,11 @@ static int ept_set_epte(struct vmx_vcpu *vcpu,
if
(
epte_present
(
*
epte
))
{
if
(
overwrite
)
ept_
clear_epte
(
epte
);
clear_epte
(
epte
);
else
{
spin_unlock
(
&
vcpu
->
ept_lock
);
printk
(
KERN_ERR
"ept: epte exists %p
\n
"
,
(
void
*
)(
*
epte
));
return
-
EINVL
;
return
-
EINV
A
L
;
}
}
...
...
@@ -387,16 +381,18 @@ static unsigned long alloc_pt_pfn(struct vmx_vcpu *vcpu) {
}
}
/*
static int free_pt_pfn(struct vmx_vcpu *vcpu,
unsigned long pfn) {
unsigned long which = pfn - (PT_PAGES_START >> PAGE_SHIFT);
if (which >= (PT_PAGES_END >> PAGE_SHIFT)) {
return
-
EINVL
;
return -EINV
A
L;
} else {
bitmap_clear(vcpu->bmp_pt_pages, which, 1);
return 0;
}
}
*/
static
int
ept_alloc_pt_item
(
struct
vmx_vcpu
*
vcpu
,
unsigned
long
*
gpfn
,
...
...
@@ -407,7 +403,7 @@ static int ept_alloc_pt_item(struct vmx_vcpu *vcpu,
ret
=
-
ENOMEM
;
}
else
{
epte_t
*
epte
;
ret
=
ept_lookup_gpa
(
vcpu
,
((
*
gpfn
)
<<
PAGE_SHIFT
),
1
,
&
epte
);
ret
=
ept_lookup_gpa
(
vcpu
,
(
void
*
)
((
*
gpfn
)
<<
PAGE_SHIFT
),
1
,
&
epte
);
if
(
!
ret
)
{
if
(
!
epte_present
(
*
epte
))
{
*
page
=
__get_free_page
(
GFP_ATOMIC
);
...
...
@@ -429,7 +425,7 @@ static int ept_gpa_to_hva(struct vmx_vcpu* vcpu,
unsigned
long
gpa
,
unsigned
long
*
hva
)
{
epte_t
*
epte
;
int
ret
=
ept_lookup_gpa
(
vcpu
,
gpa
,
0
,
&
epte
);
int
ret
=
ept_lookup_gpa
(
vcpu
,
(
void
*
)
gpa
,
0
,
&
epte
);
if
(
ret
)
{
printk
(
KERN_ERR
"ept: failed to lookup GPA: %p
\n
"
,
(
void
*
)
gpa
);
...
...
@@ -453,7 +449,7 @@ static int map_gva_to_gpa(struct vmx_vcpu *vcpu,
int
create
,
int
overwrite
)
{
int
ret
=
0
;
unsigned
long
gpfn
,
page
;
epte_t
*
epte
;
/*
epte_t *epte;
*/
pud_t
*
pud_dir
,
*
pud
;
pmd_t
*
pmd_dir
,
*
pmd
;
...
...
@@ -538,8 +534,9 @@ static int map_gva_to_gpa(struct vmx_vcpu *vcpu,
if
(
!
pte_present
(
*
pte
)
||
overwrite
)
{
set_pte
(
pte
,
__pte
((
gpa
&
PTE_PFN_MASK
)
|
__PAGE_KERNEL_EXEC
));
}
else
{
printk
(
KERN_ERR
"mm: pte conflicts %p %p
\n
"
,
(
void
*
)
gpa
,
(
void
*
)(
*
pte
));
ret
=
-
EINVL
;
printk
(
KERN_ERR
"mm: pte conflicts %p %p
\n
"
,
(
void
*
)
gpa
,
(
void
*
)
pte_val
(
*
pte
));
ret
=
-
EINVAL
;
}
return
ret
;
...
...
@@ -621,7 +618,7 @@ static int vmx_setup_initial_page_table(struct vmx_vcpu *vcpu) {
unsigned
long
gpa
,
hpa
,
gva
;
/* Map guest page table structure's pages in ept */
for
(
i
=
0
,
gpa
=
PT_PAGES_START
;
i
<
NR_PT_PAGES
,
gpa
+=
PAGE_SIZE
;
++
i
)
{
i
<
NR_PT_PAGES
;
gpa
+=
PAGE_SIZE
,
++
i
)
{
hpa
=
__get_free_page
(
GFP_KERNEL
);
if
(
!
hpa
)
return
-
ENOMEM
;
...
...
@@ -767,8 +764,8 @@ static void __vmx_setup_cpu(void) {
vmcs_writel
(
HOST_GDTR_BASE
,
gdt
->
address
);
/* 22.2.4 */
/* No sysenter should be called */
rdmsrl
(
MSR_IA32_SYSENTER_ESP
,
0
);
vmcs_writel
(
HOST_IA32_SYSENTER_ESP
,
0
);
/* 22.2.3 */
rdmsrl
(
MSR_IA32_SYSENTER_ESP
,
sysenter_esp
);
vmcs_writel
(
HOST_IA32_SYSENTER_ESP
,
sysenter_esp
);
/* 22.2.3 */
rdmsrl
(
MSR_FS_BASE
,
tmpl
);
vmcs_writel
(
HOST_FS_BASE
,
tmpl
);
/* 22.2.4 */
...
...
@@ -827,7 +824,7 @@ static void vmx_put_cpu(struct vmx_vcpu *vcpu) {
}
static
__init
int
adjust_vmx_controls
(
u32
ctl_min
,
u32
ctl_opt
,
static
int
adjust_vmx_controls
(
u32
ctl_min
,
u32
ctl_opt
,
u32
msr
,
u32
*
result
)
{
u32
vmx_msr_low
,
vmx_msr_high
;
u32
ctl
=
ctl_min
|
ctl_opt
;
...
...
@@ -877,7 +874,7 @@ static void vmx_dump_cpu(struct vmx_vcpu *vcpu) {
printk
(
KERN_INFO
"vmx: --- End VCPU Dump ---
\n
"
);
}
static
__init
int
setup_vmcs_config
(
struct
vmcs_config
*
vmcs_conf
)
{
static
int
setup_vmcs_config
(
struct
vmcs_config
*
vmcs_conf
)
{
u32
vmx_msr_low
,
vmx_msr_high
;
u32
min
,
opt
,
min2
,
opt2
;
u32
_pin_based_exec_control
=
0
;
...
...
@@ -930,7 +927,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf) {
&
_cpu_based_2nd_exec_control
)
<
0
)
return
-
EIO
;
}
else
{
printk
(
KERN_ERR
"lcd: secondary VME controls not supported
\n
"
)
printk
(
KERN_ERR
"lcd: secondary VME controls not supported
\n
"
)
;
return
-
EIO
;
}
...
...
@@ -939,7 +936,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf) {
rdmsr
(
MSR_IA32_VMX_EPT_VPID_CAP
,
vmx_capability
.
ept
,
vmx_capability
.
vpid
);
}
else
{
printk
(
KERN_ERR
"lcd: EPT not supported
\n
"
)
printk
(
KERN_ERR
"lcd: EPT not supported
\n
"
)
;
return
-
EIO
;
}
...
...
@@ -1216,7 +1213,7 @@ static void vmx_free_vpid(struct vmx_vcpu *vmx)
static
void
vmx_setup_initial_guest_state
(
struct
vmx_vcpu
*
vcpu
)
{
unsigned
long
tmpl
;
/*
unsigned long tmpl;
*/
unsigned
long
cr4
=
X86_CR4_PAE
|
X86_CR4_VMXE
|
X86_CR4_OSXMMEXCPT
|
X86_CR4_PGE
|
X86_CR4_OSFXSR
;
/* if (boot_cpu_has(X86_FEATURE_PCID)) */
...
...
@@ -1231,7 +1228,7 @@ static void vmx_setup_initial_guest_state(struct vmx_vcpu *vcpu)
X86_CR0_MP
|
X86_CR0_ET
|
X86_CR0_NE
);
vmcs_writel
(
CR0_READ_SHADOW
,
X86_CR0_PG
|
X86_CR0_PE
|
X86_CR0_WP
|
X86_CR0_MP
|
X86_CR0_ET
|
X86_CR0_NE
);
vmcs_writel
(
GUEST_CR3
,
LCD_CR3_VAL
);
vmcs_writel
(
GUEST_CR3
,
vcpu
->
pt_gpa
);
vmcs_writel
(
GUEST_CR4
,
cr4
);
vmcs_writel
(
CR4_READ_SHADOW
,
cr4
);
vmcs_writel
(
GUEST_IA32_EFER
,
EFER_LME
|
EFER_LMA
|
...
...
@@ -1240,7 +1237,7 @@ static void vmx_setup_initial_guest_state(struct vmx_vcpu *vcpu)
vmcs_writel
(
GUEST_GDTR_LIMIT
,
GDT_SIZE
);
vmcs_writel
(
GUEST_IDTR_BASE
,
LCD_IDT_ADDR
);
vmcs_writel
(
GUEST_IDTR_LIMIT
,
IDT_ENTRIES
*
16
);
vmcs_writel
(
GUEST_RIP
,
LCD_CODE_
START
);
vmcs_writel
(
GUEST_RIP
,
LCD_CODE_
ADDR
);
vmcs_writel
(
GUEST_RSP
,
LCD_STACK_ADDR
);
vmcs_writel
(
GUEST_RFLAGS
,
0x02
);
vmcs_writel
(
GUEST_DR7
,
0
);
...
...
@@ -1304,9 +1301,13 @@ static void vmx_setup_initial_guest_state(struct vmx_vcpu *vcpu)
}
static
int
setup_gdt
(
struct
vmx_vcpu
*
vcpu
)
{
struct
desc_struct
*
desc
;
tss_desc
*
tssd
;
struct
x86_hw_tss
*
tss
;
memset
(
vcpu
->
gdt
,
0
,
GDT_SIZE
);
struct
desc_struct
*
desc
=
vcpu
->
gdt
+
GDT_ENTRY_KERNEL_CS
;
desc
=
vcpu
->
gdt
+
GDT_ENTRY_KERNEL_CS
;
/* ignored fields according to APM Vol.3 Ch4.8 */
/* code seg desc */
desc
->
type
=
SEG_TYPE_CODE
|
SEG_TYPE_EXEC_READ
;
...
...
@@ -1323,12 +1324,12 @@ static int setup_gdt(struct vmx_vcpu* vcpu) {
desc
->
p
=
1
;
/* task segment desc value */
tss
_desc
*
tss
=
(
tss_desc
*
)(
vcpu
->
gdt
+
GDT_ENTRY_TSS
);
set_tssldt_descriptor
(
tss
,
LCD_TSS_ADDR
,
DESC_TSS
,
LCD_TSS_SIZE
);
tss
d
=
(
tss_desc
*
)(
vcpu
->
gdt
+
GDT_ENTRY_TSS
);
set_tssldt_descriptor
(
tss
d
,
LCD_TSS_ADDR
,
DESC_TSS
,
LCD_TSS_SIZE
);
/* TSS segment */
memset
(
vcpu
->
tss
,
0
,
LCD_TSS_SIZE
);
struct
x86_hw_tss
*
tss
=
&
vcpu
->
tss
->
tss
;
tss
=
&
vcpu
->
tss
->
tss
;
tss
->
sp0
=
LCD_STACK_ADDR
;
tss
->
io_bitmap_base
=
offsetof
(
struct
lcd_tss_struct
,
io_bitmap
);
tss
->
ist
[
0
]
=
LCD_TSS_ADDR
+
(
PAGE_SIZE
>>
1
);
...
...
@@ -1337,7 +1338,7 @@ static int setup_gdt(struct vmx_vcpu* vcpu) {
return
0
;
}
static
int
setup_idt
(
vmx_vcpu
*
vcpu
)
{
static
void
setup_idt
(
struct
vmx_vcpu
*
vcpu
)
{
int
i
;
memset
(
vcpu
->
idt
,
0
,
PAGE_SIZE
);
/* Just fill the IDT */
...
...
@@ -1347,15 +1348,17 @@ static int setup_idt(vmx_vcpu* vcpu) {
}
}
static
struct
vmx_vcpu
*
vmx_create_vcpu
()
{
static
struct
vmx_vcpu
*
vmx_create_vcpu
(
void
)
{
struct
vmx_vcpu
*
vcpu
=
kmalloc
(
sizeof
(
struct
vmx_vcpu
),
GFP_KERNEL
);
if
(
!
vcpu
)
return
NULL
;
memset
(
vcpu
,
0
,
sizeof
(
*
vcpu
));
vcpu
->
bmp_pt_pages
=
kmalloc
(
sizeof
(
long
)
*
BITS_TO_LONGS
(
NR_PT_PAGES
));
if
(
!
vcpu
->
bmp_at_page
)
vcpu
->
bmp_pt_pages
=
kmalloc
(
sizeof
(
long
)
*
BITS_TO_LONGS
(
NR_PT_PAGES
),
GFP_KERNEL
);
if
(
!
vcpu
->
bmp_pt_pages
)
goto
fail_bmp
;
bitmap_zero
(
vcpu
->
bmp_pt_pages
,
NR_PT_PAGES
);
...
...
@@ -1367,7 +1370,7 @@ static struct vmx_vcpu * vmx_create_vcpu() {
if
(
!
vcpu
->
idt
)
goto
fail_idt
;
vcpu
->
tss
=
(
struct
lcd_tss_struct
)
__get_free_page
(
GFP_KERNEL
);
vcpu
->
tss
=
(
struct
lcd_tss_struct
*
)
__get_free_page
(
GFP_KERNEL
);
if
(
!
vcpu
->
tss
)
goto
fail_tss
;
...
...
@@ -1390,22 +1393,22 @@ static struct vmx_vcpu * vmx_create_vcpu() {
goto
fail_ept
;
vcpu
->
eptp
=
construct_eptp
(
vcpu
->
ept_root
);
vmx_get_cpu
(
vcpu
);
vmx_setup_vmcs
(
vcpu
);
vmx_setup_initial_guest_state
();
setup_gdt
(
vcpu
);
setup_idt
(
vcpu
);
vmx_put_cpu
(
vcpu
);
if
(
cpu_has_vmx_ept_ad_bits
())
{
vcpu
->
ept_ad_enabled
=
true
;
printk
(
KERN_INFO
"vmx: enabled EPT A/D bits"
);
}
if
(
vmx_create_ept
(
vcpu
))
{
printk
(
KERN_ERR
O
"vmx: creating EPT failed."
);
printk
(
KERN_ERR
"vmx: creating EPT failed."
);
goto
fail_ept
;
}
vmx_get_cpu
(
vcpu
);
vmx_setup_vmcs
(
vcpu
);
vmx_setup_initial_guest_state
(
vcpu
);
setup_gdt
(
vcpu
);
setup_idt
(
vcpu
);
vmx_put_cpu
(
vcpu
);
return
vcpu
;
fail_ept:
...
...
@@ -1413,7 +1416,7 @@ fail_ept:
fail_vpid:
vmx_free_vmcs
(
vcpu
->
vmcs
);
fail_vmcs:
kfree
(
vcpu
->
isr_page
);
kfree
(
(
void
*
)
vcpu
->
isr_page
);
fail_isr:
kfree
(
vcpu
->
tss
);
fail_tss:
...
...
@@ -1422,7 +1425,7 @@ fail_idt:
kfree
(
vcpu
->
gdt
);
fail_gdt:
kfree
(
vcpu
->
bmp_pt_pages
);
fail_
g
mp:
fail_
b
mp:
kfree
(
vcpu
);
return
NULL
;
...
...
@@ -1638,14 +1641,14 @@ int vmx_launch(int64_t *ret_code) {
vmx_put_cpu
(
vcpu
);
if
(
ret
==
EXIT_REASON_EPT_VIOLATION
)
if
(
ret
==
EXIT_REASON_EPT_VIOLATION
)
{
done
=
vmx_handle_ept_violation
(
vcpu
);
}
else
if
(
ret
!=
EXIT_REASON_EXTERNAL_INTERRUPT
)
{
}
else
{
//
if (ret != EXIT_REASON_EXTERNAL_INTERRUPT) {
printk
(
KERN_INFO
"unhandled exit: reason %d, exit qualification %x
\n
"
,
ret
,
vmcs_read32
(
EXIT_QUALIFICATION
));
vmx_dump_cpu
(
vcpu
);
done
=
1
;
}
}
if
(
done
||
vcpu
->
shutdown
)
break
;
...
...
@@ -1660,7 +1663,7 @@ int vmx_launch(int64_t *ret_code) {
return
0
;
}
static
__init
int
__vmx_enable
(
struct
vmcs
*
vmxon_buf
)
{
static
int
__vmx_enable
(
struct
vmcs
*
vmxon_buf
)
{
u64
phys_addr
=
__pa
(
vmxon_buf
);
u64
old
,
test_bits
;
...
...
@@ -1687,7 +1690,7 @@ static __init int __vmx_enable(struct vmcs *vmxon_buf) {
return
0
;
}
static
__init
void
vmx_enable
(
void
*
unused
)
{
static
void
vmx_enable
(
void
*
unused
)
{
int
ret
;
struct
vmcs
*
vmxon_buf
=
__get_cpu_var
(
vmxarea
);
...
...
@@ -1802,11 +1805,13 @@ void vmx_exit(void)
free_page
((
unsigned
long
)
msr_bitmap
);
}
static
task_struct
*
test_thread
;
static
int
lcd_thread
(
void
)
{
static
struct
task_struct
*
test_thread
;
static
int
lcd_test
(
void
)
{
int
ret
;
int64_t
ret_code
;
printk
(
"LCD: start launching vmx
\n
"
);
ret
=
vmx_launch
(
&
ret_code
);
if
(
ret
)
{
printk
(
KERN_ERR
"LCD: launch failure %d
\n
"
,
ret
);
...
...
@@ -1814,21 +1819,29 @@ static int lcd_thread(void) {
printk
(
KERN_INFO
"LCD: launch OK
\n
"
);
}
printk
(
KERN_INFO
"LCD: ret code: %ld
\n
"
,
ret_code
);
printk
(
KERN_INFO
"LCD: ret code: %llu
\n
"
,
ret_code
);
return
ret
;
}
static
int
lcd_thread
(
void
*
d
)
{
int
ret
=
lcd_test
();
do_exit
(
ret
);
return
0
;
// avoid compiler warning
}
static
void
__init
lcd_init
(
void
)
{
static
int
__init
lcd_init
(
void
)
{
int
r
;
printk
(
KERN_INFO
"LCD module loaded
\n
"
);
if
((
r
=
vmx_init
()))
{
printk
(
KERN_ERR
"LCD: failed to init VMX
\n
"
);
}
else
{
r
=
lcd_test
();
/*
test_thread = kthread_create(&lcd_thread, NULL, "LCD");
if (!test_thread) {
printk(KERN_ERR "LCD: test thread failed to create\n");
}
*/
}
return
r
;
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment