当前位置:网站首页>China Southern Airlines pa3.1
China Southern Airlines pa3.1
2022-07-07 10:38:00 【yym68686】
Catalog
- Thinking questions
- 1. What is an operating system ?(5)
- 2. We don't ⼀ sample , Do you ?(5)
- 3. The essence of the operating system (5)
- 4. Is the program really over ?(10)
- 5. Trigger system debugging ⽤(10)
- 6. What's the difference ?(5)
- 7. Segment error (10)
- 8. Yes ⽐ Exceptions and function adjustments ⽤(5)
- 9. Weird code (5)
- 10. Pay attention to distinguish between event number and system call ⽤ Number (5)
- 11. Can't print out ?(5)
- 12. understand ⽂ Piece management function (15)
- 13. No longer mysterious secret skill (5)
- 14. Will answer (5)
- Experimental content
- Realization loader(10 branch )
- Add registers and LIDT Instructions (10 branch )
- Realization INT Instructions (10 branch )
- Implement other related instructions and structures (15 branch )
- Improve event distribution and do_syscall(15 branch )
- Realize heap management (10 branch )
- Realize system debugging ⽤(10 branch )
- Successful transportation ⾏ Each test ⽤ example (20 branch )
- References
Course documentation :
Project address :
GitHub - yym68686/ics2022: NUAA PA ics2022
Thinking questions
1. What is an operating system ?(5)
This is a big problem , You can talk briefly about your initial impression . We also encourage you to come back and re-examine this problem after learning the operating system course .
- An operating system is software that automatically runs programs , Be responsible for allocating system resources , Let the program run in order
2. We don't ⼀ sample , Do you ?(5)
We are PA2 Chinese vs cputest And some equipment testing programs run directly in AM above , So and Nanos-lite Is running on the AM Above
What's the difference ? We can Nanos-lite As a and PA2 One of these test cases in the same position AM Procedure ?
- No,
- Sure
3. The essence of the operating system (5)
We put PA2 The way these test cases run in is called “ User programs that run directly on hardware ”, After thinking about the last question , Please summarize the essence of the operating system : The operating system is a relatively large ( ), It is similar to programs that run directly on hardware ( )( Yes / nothing ) Substantial differences .
- The operating system is a relatively large software
- It's no different from programs that run directly on hardware
4. Is the program really over ?(10)
We once asked such a question : In the program design class, the teacher said that the program runs until main()
Functional return 0;
sentence , The program is over , Is it true that ? Now in retrospect , Whether my answer was correct at that time . The program is entering main Before and after function main After the function , What has been done ? If you don't understand , Please combine _start()
And the function or procedure called in it .
main Before function execution , It is mainly to initialize system related resources :
- Set the stack pointer
- initialization static Static and global Global variables , namely data The content of the paragraph
- Initial the uninitialized part : Numerical type short,int,long Wait for 0,bool by FALSE, Pointer for NULL, wait , namely .bss The content of the paragraph
- Run the global constructor ,C++ Middle constructor
- take main The parameters of the function ,argc,argv Wait for it to pass on to main function , Then it really runs main function
main Function will perform the opposite work .
5. Trigger system debugging ⽤(10)
Please refer to the above , Trigger a write screen operation by directly calling the system call .
Write code :
const char str[] = "Hello world!\n";
int main() {
asm volatile ("movl $4, %eax;" // system call ID, 4 = SYS_write
"movl $1, %ebx;" // file descriptor, 1 = stdout
"movl $str, %ecx;" // buffer address
"movl $13, %edx;" // length
"int $0x80");
return 0;
}
Compile operation :
[ics2022] gcc 1.c -o 1
[ics2022] ./1
Hello world!
6. What's the difference ?(5)
We found that , The system call will be based on the system call number in IDT Middle index , Get the address of the system call service program corresponding to the call number , And jump over . Before triggering the system call , It will protect the user related status register (EFLAGS, EIP etc. ) Go to the stack , Recover after the system call , This is very similar to what we have learned ? We can understand the service program of system call as a special “ function ” Do you ? Please give reasons . This “ Service program ” And our “ User written functions ” What's the difference ?
- Similar to the function call process
- Sure .
- Authority is different
7. Segment error (10)
We are GNU/Linux The following is written with bug The program , Although it can be compiled , But when running, I encountered “Segmentation Fault”( Segment error ), Why can't you find these potential segment errors in the compilation phase ? What program behaviors usually cause segment errors ?
- Access out of bounds is not a syntax error
- It may be caused by the array out of bounds , Unsafe function used (
gets
) Caused by or the use of wild pointers
8. Yes ⽐ Exceptions and function adjustments ⽤(5)
We know that when making a function call, we also need to save the caller's state : The return address , And the calling convention (calling convention) Registers that need to be saved by the caller in . However, more information should be saved before exception handling . Try to compare them , And think about what causes the difference between the two in preserving information .
- Exception handling is due to an error , It may be necessary to re execute the command , Need to keep more information
- And function call is the normal execution process of the program
9. Weird code (5)
trap.S
There's a line in it pushl %esp
Code for , At first glance, its behavior is very strange . Can you combine the code before and after to understand its behavior ?Hint: Don't think too much , In fact, it's all the knowledge you've learned .
- Keep the top of the stack , So that after the function call , Restore the top of the stack
10. Pay attention to distinguish between event number and system call ⽤ Number (5)
What is the difference between event number and system call number ?
- The event number is the number of the abnormal interrupt
- The system call number is when the event number is
80
When a system call is triggeredeax
Register value
11. Can't print out ?(5)
Please input the above program , Be sure not to make any mistakes , Make sure it is entered as is ( Of course , You don't need to enter comments ), Otherwise, you may not accidentally appear the paragraph error here . Please combine the handout with your own experiment , Try to find a solution , And explain the reason .
modify :
#include <stdio.h>
int main(){
int *p = NULL;
- printf("I am here!");
+ printf("I am here!\n");
*p = 10; // giving value to a NULL address will cause segmentation fault
return 0;
}
Or use fflush(stdout)
:
#include <stdio.h>
int main(){
int *p = NULL;
printf("I am here!");
+ fflush(stdout);
*p = 10; // giving value to a NULL address will cause segmentation fault
return 0;
}
Compile operation :
[ics2022] gcc 1.c -o 1
[ics2022] ./1
I am here!
[1] 4032 segmentation fault ./1
reason :
printf Called stdout It is buffered by line , Add a line break to output the current buffer first , When you encounter errors later .fflush(stdout)
The same effect .
12. understand ⽂ Piece management function (15)
Convenience , We have implemented several file management functions for you in the updated framework code . that , Please refer to these fs_
Initial function , Think about how they are written
utilize
:vim /fs_close(/ ~/ics2022/** | copen
Find such functions in nanos-lite/src/fs.c
Inside , for example :
ssize_t fs_read(int fd, void *buf, size_t len) {
assert(fd > 2);
if (fd == FD_EVENTS) {
return events_read(buf, len);
}
Finfo *f = file_table + fd;
int remain_bytes = f->size - f->open_offset;
int bytes_to_read = (remain_bytes > len ? len : remain_bytes);
if (fd == FD_DISPINFO) {
dispinfo_read(buf, f->disk_offset + f->open_offset, bytes_to_read);
}
else {
ramdisk_read(buf, f->disk_offset + f->open_offset, bytes_to_read);
}
f->open_offset += bytes_to_read;
return bytes_to_read;
}
fs_open()
Match the file name parameter to the file descriptor table and return the subscript , If you don't find it, you will report it wrongfs_read()
adoptfd
Parameter to get the file offset and length , Again fromramdisk
ordispinfo
Read data tobuf
infs_write()
adoptfd
Choose how to write . If the document is written , Then calculate the offset and read length for file reading and writingfs_lseek()
adoptwhence
Choose how to move the file offset , Then assign the new offset to the corresponding file descriptorfs_close()
Go straight back to0
, Because there's no need forclose
13. No longer mysterious secret skill (5)
On the Internet, there are some secret skills about the legend of fairy sword and Qixia , Some of the secrets are as follows :
- Many people will go to get money three times when they arrive at Aunt Yun , In fact, taking it once will fill the cash box ! You take the money once and buy a sword. When you use the money, there are only more than 1000 , Then go to the Taoist , Don't go upstairs yet , Go to the shopkeeper to buy wine , Buy more times and you'll find that you can't use up your money .
- Constantly use one throw of heaven and earth ( The money must be more than 5000 Wen ) Use less than 5000 yuan of property , Money will soar to the ceiling , In this way, there will be endless money .
- When Li Xiaoyao reaches the level 99 Class time , use 5~10 Golden silkworm King , Experience points come out again , And the experience required for upgrading will return to the initial stage 5~10 Experience value within level , Then fight the enemy or upgrade with the golden silkworm King , You can learn the magic of linger ( From the five Qi Dynasty yuan ); Rise to 199 Use after grade 5~10 Golden silkworm King , Experience points and then come out , The upgrade experience required is also very low , You can learn the magic of moon ( Start with a Yang finger ); To 299 Use after grade 10~30 Golden silkworm King , Continue to upgrade after the experience points come out , Can learn the magic of Anu ( Start with the ten thousand ant eclipse ).
Suppose these above secret skills are not the intention of the game makers , Please try to explain why these secret skills can work .
- game bug, Maybe the condition judgment is not careful
14. Will answer (5)
The specific process of document reading and writing There are the following behaviors in the legend of Xianjian Qixia :
- stay
navy-apps/apps/pal/src/global/global.c
OfPAL_LoadGame()
Pass throughfread()
Read the game archive - stay
navy-apps/apps/pal/src/hal/hal.c
Ofredraw()
Pass throughNDL_DrawRect()
Update screen
Please explain the legend of fairy sword with the code 、 Library function 、libos、Nanos-lite、AM、NEMU How to help each other , To read the game archive and update the screen respectively .
- The compiled program is saved in
ramdisk
In file make run
First runnemu
, And then innemu
Up operationNanos-lite
Nanos-lite
Ofmain
Use in a functionloader
The load is located atramdisk
Storage area ( Actually exists in memory ) Of/bin/pal
Programloader
Function fromramdisk
file ( disk ) Read the program into the memory area , After some initialization , Then turn the control to Xianjianmain
Entry function- Fairy sword program calls library functions and
Nanos-lite
The self-defined library function in completes the operation of the program , Including the reading and writing of documentsUI
Display and so on .
Experimental content
Before the experiment :
git commit --allow-empty -am "before starting pa3"
git checkout -b pa3
Realization loader(10 branch )
stay nanos-lite/src/main.c
Ding Yihong HAS_ASYE
,loader()
Function in nanos-lite/src/loader.c
In the definition of , Open file :
vim ~/ics2022/nanos-lite/src/loader.c
ramdisk_read
And access ramdisk
Of length get_ramdisk_size
Functions are all in ~/ics2022/nanos-lite/src/ramdisk.c
Definition . According to the handout ramdisk_read The first parameter is zero DEFAULT_ENTRY
, The second parameter offset is 0, The third parameter is ramdisk
Size , It can be used get_ramdisk_size
Function to obtain , complete loader function :
uintptr_t loader(_Protect *as, const char *filename) {
ramdisk_read(DEFAULT_ENTRY, 0, get_ramdisk_size());
return (uintptr_t)DEFAULT_ENTRY;
}
Declare external functions :
void ramdisk_read(void *, uint32_t, uint32_t);
size_t get_ramdisk_size();
compile navy-apps/tests/dummy/dummy.c:
cd ~/ics2022/navy-apps/tests/dummy/ && make
compile Newlib There will be more warning, We can ignore them . stay NEMU With the latest version ramdisk Of Nanos-lite:
cd ~/ics2022/nanos-lite/ && make update && make run
Press c After operation , Find out :
invalid opcode(eip = 0x04001ec0): cd 80 5b 5d c3 66 90 90 ...
There are two cases which will trigger this unexpected exception:
1. The instruction at eip = 0x04001ec0 is not implemented.
2. Something is implemented incorrectly.
Find this eip(0x04001ec0) in the disassembling result to distinguish which case it is.
If it is the first case, see
_ ____ ___ __ __ __ _
(_)___ \ / _ \ / / | \/ | | |
_ __) | (_) |/ /_ | \ / | __ _ _ __ _ _ __ _| |
| ||__ < > _ <| '_ \ | |\/| |/ _` | '_ \| | | |/ _` | |
| |___) | (_) | (_) | | | | | (_| | | | | |_| | (_| | |
|_|____/ \___/ \___/ |_| |_|\__,_|_| |_|\__,_|\__,_|_|
for more details.
If it is the second case, remember:
* The machine is always right!
* Every line of untested code is always wrong!
0xcd yes int Ib
Instructions , This explanation loader Successfully loaded dummy, And successfully jump to dummy To perform the . Consistent with the handout instructions .
Add registers and LIDT Instructions (10 branch )
i386 Provide int
Instruction as exception instruction , The whole process is made up of i386 Supported by interrupt mechanism , The above jump target is through the door descriptor (Gate Descriptor) To indicate . The door descriptor is a 8 Byte structure , It contains a lot of detailed information .i386 Interpret a certain section of data in memory into an array , It's called IDT(Interrupt Descriptor Table, Interrupt descriptor table ), An element of an array is a gate descriptor .
In order to find IDT,i386 Use IDTR Register to store IDT First address and length of . The code of the operating system puts IDT Get ready , Then execute a special instruction lidt
(Load Interrupt Descriptor Table), Come on IDTR Set the IDT First address and length of , This interrupt processing mechanism can work normally .
- according to i386 ⼿ Add the album correctly IDTR and CS register
IDTR The format of the register can be referred to i386 Section in the manual 156 page , among LIMIT 16 position ,BASE 32 position .i386 Manual No 159 page Figure 9-5, Tips CS The register is 16 position , So in ~/ics2022/nemu/include/cpu/reg.h
Add the following line :
typedef struct {
union{
struct {
union{
uint32_t _32;
uint16_t _16;
uint8_t _8[2];
};
} gpr[8];
struct {
rtlreg_t eax, ecx, edx, ebx, esp, ebp, esi, edi;
};
};
/* Do NOT change the order of the GPRs' definitions. */
/* In NEMU, rtlreg_t is exactly uint32_t. This makes RTL instructions
* in PA2 able to directly access these registers.
*/
union {
struct{
uint32_t CF : 1;
uint32_t : 5;
uint32_t ZF : 1;
uint32_t SF : 1;
uint32_t : 1;
uint32_t IF : 1;
uint32_t : 1;
uint32_t OF : 1;
uint32_t : 20;
};
rtlreg_t value;
} eflags;
vaddr_t eip;
+ struct {
+ uint32_t base; // 32 position base
+ uint16_t limit; // 16 position limit
+ }idtr;
+ uint16_t cs;
} CPU_state;
And then in nanos-lite/src/main.c
Ding Yihong HAS_ASYE
.
- stay restart() Set the initial value of the register correctly
stay ics2022/nemu/src/monitor/monitor.c
modify restart()
function :
static inline void restart() {
/* Set the initial instruction pointer. */
cpu.eip = ENTRY_START;
cpu.eflags.value = 0x2;
cpu.cs = 0x8;
#ifdef DIFF_TEST
init_qemu_reg();
#endif
}
- LIDT Instruction details can be found in i386 ⼿ Found in the book
i386 Manual No 330 page ,LIDT Instruction pseudo code :
IF instruction = LIDT
THEN
IF OperandSize = 16
THEN IDTR.Limit:Base ← m16:24 (* 24 bits of base loaded *)
ELSE IDTR.Limit:Base ← m16:32
FI;
ELSE (* instruction = LGDT *)
IF OperandSize = 16
THEN GDTR.Limit:Base ← m16:24 (* 24 bits of base loaded *)
ELSE GDTR.Limit:Base ← m16:32;
FI;
FI;
if OperandSize
yes 16, be limit Read 16 position , Express IDT The length of the array ,base Read 24 position , Express IDT The starting address of the array , if OperandSize
yes 32, be limit Read 16 position ,base Read 32 position . adopt IDTR Address pairs in IDT When indexing , Need to use vaddr_read()
, stay nemu/src/cpu/exec/system.c
Fill in lidt
function :
make_EHelper(lidt) {
cpu.idtr.limit = vaddr_read(id_dest->addr, 2); //limit 16 position
if (decoding.is_operand_size_16)
cpu.idtr.base = vaddr_read(id_dest->addr + 2, 3);//base 24 position
else
cpu.idtr.base = vaddr_read(id_dest->addr + 2, 4);//base 32 position
print_asm_template1(lidt);
}
At the same time, find in the seventh instruction group LIDT Instructions , Complete the operation code table :
/* 0x0f 0x01*/
make_group(gp7,
EMPTY, EMPTY, EMPTY, EX(lidt),
EMPTY, EMPTY, EMPTY, EMPTY)
stay src/cpu/exec/all-instr.h
Add the function declaration .
Realization INT Instructions (10 branch )
- The implementation is written in raise_intr() Function
It is mentioned in the handout : The hardware processing after triggering the exception is as follows :
- In turn EFLAGS, CS( Code segment register ), EIP Value stack of register
- from IDTR Middle readout IDT The first address
- According to the exception number in IDT Index in , Find a door descriptor
- Set offset Domains are combined into destination addresses
stay nemu/src/cpu/intr.c
Li Fuquan raise_intr
function :
void raise_intr(uint8_t NO, vaddr_t ret_addr) {
/* TODO: Trigger an interrupt/exception with ``NO''. * That is, use ``NO'' to index the IDT. */
// Get the door descriptor
vaddr_t gate_addr = cpu.idtr.base + 8 * NO;
//P Bit check
if (cpu.idtr.limit < 0) assert(0);
// take eflags、cs、 Return address stack
t0 = cpu.cs; //cpu.cs Only 16 position , Need to be converted to 32 position
rtl_push(&cpu.eflags.value);
rtl_push(&t0);
rtl_push(&ret_addr);
// Composite interrupt handler entry point
uint32_t high, low;
low = vaddr_read(gate_addr, 4) & 0xffff;
high = vaddr_read(gate_addr + 4, 4) & 0xffff0000;
// Set up eip Jump
decoding.jmp_eip = high | low;
decoding.is_jmp = true;
}
- send ⽤ INT Of helper A function ⽤ raise_intr()
void raise_intr(uint8_t NO, vaddr_t ret_addr); // Add the statement
make_EHelper(int) {
raise_intr(id_dest->val, decoding.seq_eip);
print_asm("int %s", id_dest->str);
#ifdef DIFF_TEST
diff_test_skip_nemu();
#endif
}
- Jump to the destination address
Complete the operation code table
/* 0xcc */ EX(int3), IDEXW(I,int,1), EMPTY, EMPTY,
stay src/cpu/exec/all-instr.h
Add the function declaration , Compile the program again after saving :
clear && cd ~/ics2022/nanos-lite/ && make update && make run
Implement other related instructions and structures (15 branch )
- organization _RegSet Structure , Need to explain why
It is mentioned in the handout : The first step of hardware processing after triggering an exception is to turn EFLAGS,CS( Code segment register ),EIP Value stack of register , After the program runs, it will trigger vecsys function ,vecsys()
Error code and exception number will be pressed #irq
, And then jump to asm_trap()
. stay asm_trap()
in , The code will save the general registers of the user process to the stack . And from that came trap frame( Trap frame ) Data structure of . So we can know trap frame The structure is :
┌────────────┐high address
│ eflag │ │
├────────────┤ │
┌───┐ │ cs │ │
│EAX│\ ├────────────┤ │
├───┤ \ │ eip │ │
│ECX│ \ ├────────────┤ │ Direction of stack growth
├───┤ \ │ error trap │ │
│EDX│ \ ├────────────┤ │
├───┤ \ │ irq │ │
│EBX│ \├────────────┤ │
├───┤ │ gpr │ ▼
│ESP│ /└────────────┘low address
├───┤ /
│EBP│ /
├───┤ /
│ESI│ /
├───┤ /
│EDI│/
└───┘
The title requires : Reorganize nexus-am/am/arch/x86-nemu/include/arch.h
As defined in _RegSet
Member of a structure , Make the order of these member declarations and nexus-am/am/arch/x86-nemu/src/trap.S
Constructed in trap frame bring into correspondence with . When restoring registers, just reverse the order , Because those who go in after the stack come out first , Reorganize _RegSet
Member of a structure :
struct _RegSet {
uintptr_t edi,esi,ebp,esp,ebx,edx,ecx,eax;
int irq;
uintptr_t error_code,eip,cs,eflags;
};
- pusha, popa, iret
Complete the instruction in the operation code table :
/* 0x60 */ EX(pusha), EX(popa), EMPTY, EMPTY,
...
/* 0xcc */ EMPTY, IDEXW(I,int,1), EMPTY, EX(iret),
stay i386 Manual No 369,364 Page found pusha,popa Instructions , According to the pseudo code in nemu/src/cpu/exec/data-mov.c
Complete the execution function :
make_EHelper(pusha) {
t0 = cpu.esp;
if(decoding.is_operand_size_16) {
rtl_lr_w(&t1, R_AX); rtl_push(&t1);
rtl_lr_w(&t1, R_CX); rtl_push(&t1);
rtl_lr_w(&t1, R_DX); rtl_push(&t1);
rtl_lr_w(&t1, R_BX); rtl_push(&t1);
rtl_push(&t0);
rtl_lr_w(&t1, R_BP); rtl_push(&t1);
rtl_lr_w(&t1, R_SI); rtl_push(&t1);
rtl_lr_w(&t1, R_DI); rtl_push(&t1);
}
else {
rtl_lr_l(&t1, R_EAX); rtl_push(&t1);
rtl_lr_l(&t1, R_ECX); rtl_push(&t1);
rtl_lr_l(&t1, R_EDX); rtl_push(&t1);
rtl_lr_l(&t1, R_EBX); rtl_push(&t1);
rtl_push(&t0);
rtl_lr_l(&t1, R_EBP); rtl_push(&t1);
rtl_lr_l(&t1, R_ESI); rtl_push(&t1);
rtl_lr_l(&t1, R_EDI); rtl_push(&t1);
}
print_asm("pusha");
}
make_EHelper(popa) {
if(decoding.is_operand_size_16) {
rtl_pop(&t1); rtl_sr_w(R_DI, &t1);
rtl_pop(&t1); rtl_sr_w(R_SI, &t1);
rtl_pop(&t1); rtl_sr_w(R_BP, &t1);
rtl_pop(&t1);
rtl_pop(&t1); rtl_sr_w(R_BX, &t1);
rtl_pop(&t1); rtl_sr_w(R_DX, &t1);
rtl_pop(&t1); rtl_sr_w(R_CX, &t1);
rtl_pop(&t1); rtl_sr_w(R_AX, &t1);
}
else {
rtl_pop(&t1); rtl_sr_l(R_EDI, &t1);
rtl_pop(&t1); rtl_sr_l(R_ESI, &t1);
rtl_pop(&t1); rtl_sr_l(R_EBP, &t1);
rtl_pop(&t1);
rtl_pop(&t1); rtl_sr_l(R_EBX, &t1);
rtl_pop(&t1); rtl_sr_l(R_EDX, &t1);
rtl_pop(&t1); rtl_sr_l(R_ECX, &t1);
rtl_pop(&t1); rtl_sr_l(R_EAX, &t1);
}
print_asm("popa");
}
according to i386 Manual No 311 Page pseudo code ,iret
Instructions are used to return from exception handling , It interprets the three elements at the top of the stack as EIP, CS, EFLAGS, And restore them . stay nemu/src/cpu/exec/system.c
completion iret function :
make_EHelper(iret) {
rtl_pop(&decoding.jmp_eip);
decoding.is_jmp = 1;
rtl_pop(&t0);
cpu.cs = (uint16_t)t0;
rtl_pop(&cpu.eflags.value);
print_asm("iret");
}
stay src/cpu/exec/all-instr.h
Add the function declaration , Compile the program again after saving :
clear && cd ~/ics2022/navy-apps/tests/dummy/ && make && cd ~/ics2022/nanos-lite/ && make update && make run
Press c After the implementation of the results :
(nemu) c
[src/main.c,19,main] 'Hello World!' from Nanos-lite
[src/main.c,20,main] Build time: 03:46:30, May 29 2022
[src/ramdisk.c,26,init_ramdisk] ramdisk info: start = 0x101980, end = 0x106cbc, size = 21308 bytes
[src/main.c,27,main] Initializing interrupt/exception handler...
[src/irq.c,5,do_event] system panic: Unhandled event ID = 8
nemu: HIT BAD TRAP at eip = 0x001000f1
If appear n86 does not have PF, May be in nanos-lite/src/main.c
Macro definition is not opened in HAS_ASYE
. Finally, if it is realized correctly, the running result should be trigger 8 Incident No .
Improve event distribution and do_syscall(15 branch )
- perfect do_event,⽬ In the previous stage, it is only necessary to identify the system debugging ⽤ Events can be
The handout requirements are : stay do_event()
To identify 8 System call event No _EVENT_SYSCALL
, And then call do_syscall()
,do_syscall()
First, through the macro SYSCALL_ARG1()
From the scene r
Get the system call parameters set before the user process , With the first parameter ( System call number ) distributed . see nanos-lite/src/syscall.c
Medium do_syscall
The definition of :
_RegSet* do_syscall(_RegSet *r) {
uintptr_t a[4];
a[0] = SYSCALL_ARG1(r);
switch (a[0]) {
default: panic("Unhandled syscall ID = %d", a[0]);
}
return NULL;
}
stay nanos-lite/src/irq.c
In a perfect do_event
function :
_RegSet* do_syscall(_RegSet *r);
static _RegSet* do_event(_Event e, _RegSet* r) {
switch (e.event) {
case _EVENT_SYSCALL:
do_syscall(r);
break;
default: panic("Unhandled event ID = %d", e.event);
}
return NULL;
}
- Add all system calls in the whole stage ⽤(none, exit, brk, open, write, read, lseek, close)
There are two levels of processing for system calls , Need to go through first switch-case Recognize that this is a system call event , Call again do_syscall Function to identify which system call .x86_32 System call through interrupt int 0x80
To achieve , register eax The system call number is stored in , At the same time, the return value of the system call is also stored in eax in .
- When the system call parameter is less than or equal to 6 Time , Parameters must be placed in registers in order ebx,ecx,edx,esi,edi ,ebp in
- When the system call parameter is greater than 6 Time , All parameters should be placed in a continuous memory area in turn , At the same time in the register ebx Save a pointer to the memory area
So the order of system call parameters is eax,ebx,ecx,edx. stay nexus-am/am/arch/x86-nemu/include/arch.h
completion SYSCALL_ARGx
:
#define SYSCALL_ARG1(r) r->eax
#define SYSCALL_ARG2(r) r->ebx
#define SYSCALL_ARG3(r) r->ecx
#define SYSCALL_ARG4(r) r->edx
perfect do_syscall()
, stay nanos-lite/src/syscall.c
Add the following code :
a[0] = SYSCALL_ARG1(r);
a[1] = SYSCALL_ARG2(r);
a[2] = SYSCALL_ARG3(r);
a[3] = SYSCALL_ARG4(r);
- add to
SYS_none
system call
According to the handout : Looking back dummy
Program , It triggers a number 0
Of SYS_none
system call . We have an agreement , This system call does nothing , Go straight back to 1
. stay nanos-lite/src/syscall.h
Enumeration type of system call found in :
enum {
SYS_none,
SYS_open,
SYS_read,
SYS_write,
SYS_exit,
SYS_kill,
SYS_getpid,
SYS_close,
SYS_lseek,
SYS_brk,
SYS_fstat,
SYS_time,
SYS_signal,
SYS_execve,
SYS_fork,
SYS_link,
SYS_unlink,
SYS_wait,
SYS_times,
SYS_gettimeofday
};
stay nanos-lite/src/syscall.c
completion do_systell
function :
_RegSet* do_syscall(_RegSet *r) {
uintptr_t a[4];
a[0] = SYSCALL_ARG1(r);
a[1] = SYSCALL_ARG2(r);
a[2] = SYSCALL_ARG3(r);
a[3] = SYSCALL_ARG4(r);
switch (a[0]) {
+ case SYS_none: r->eax = 1; break;
default: panic("Unhandled syscall ID = %d", a[0]);
}
- add to
SYS_exit
system call
stay nanos-lite/src/syscall.c
completion do_systell
function :
_RegSet* do_syscall(_RegSet *r) {
uintptr_t a[4];
a[0] = SYSCALL_ARG1(r);
a[1] = SYSCALL_ARG2(r);
a[2] = SYSCALL_ARG3(r);
a[3] = SYSCALL_ARG4(r);
switch (a[0]) {
case SYS_none: r->eax = 1; break;
+ case SYS_exit: _halt(a[1]); break;
default: panic("Unhandled syscall ID = %d", a[0]);
}
Run again dummy Program :
clear && cd ~/ics2022/navy-apps/tests/dummy/ && make && cd ~/ics2022/nanos-lite/ && make update && make run
Running results :
(nemu) c
[src/main.c,19,main] 'Hello World!' from Nanos-lite
[src/main.c,20,main] Build time: 20:45:48, May 29 2022
[src/ramdisk.c,26,init_ramdisk] ramdisk info: start = 0x101a80, end = 0x106dbc, size = 21308 bytes
[src/main.c,27,main] Initializing interrupt/exception handler...
nemu: HIT GOOD TRAP at eip = 0x001000f1
- add to
SYS_brk
system call - add to
SYS_open
system call - add to
SYS_write
system call
modify nanos-lite/Makefile
:
NAME = nanos-lite
SRCS = $(shell find -L ./src/ -name "*.c" -o -name "*.cpp" -o -name "*.S")
LIBS = klib
include $(AM_HOME)/Makefile.app
FSIMG_PATH = $(NAVY_HOME)/fsimg
RAMDISK_FILE = build/ramdisk.img
OBJCOPY_FLAG = -S --set-section-flags .bss=alloc,contents -O binary
- OBJCOPY_FILE = $(NAVY_HOME)/tests/dummy/build/dummy-x86
+ OBJCOPY_FILE = $(NAVY_HOME)/tests/hello/build/hello-x86
.PHONY: update update-ramdisk-objcopy update-ramdisk-fsimg update-fsimg
update-ramdisk-objcopy:
$(OBJCOPY) $(OBJCOPY_FLAG) $(OBJCOPY_FILE) $(RAMDISK_FILE)
touch src/files.h
update-fsimg:
$(MAKE) -s -C $(NAVY_HOME) ISA=$(ISA)
update-ramdisk-fsimg: update-fsimg
$(eval FSIMG_FILES := $(shell find $(FSIMG_PATH) -type f))
@for f in $(FSIMG_FILES); do \
if $(READELF) -h $$f 2> /dev/null > /dev/null; then \
$(OBJCOPY) $(OBJCOPY_FLAG) $$f; \
fi \
done
@cat $(FSIMG_FILES) > $(RAMDISK_FILE)
@wc -c $(FSIMG_FILES) | grep -v 'total$$' | sed -e 's+ $(FSIMG_PATH)+ +' | awk -v sum=0 '{print "\x7b\x22" $$2 "\x22\x2c " $$1 "\x2c " sum "\x7d\x2c";sum += $$1}' > src/files.h
src/syscall.h: $(NAVY_HOME)/libs/libos/src/syscall.h
ln -sf $^ [email protected]
update: update-ramdisk-objcopy src/syscall.h
@touch src/initrd.S
Implement according to the handout sys_write
step :
- stay
do_syscall()
The system call number identified in isSYS_write
after , Checkfd
Value , Iffd
yes1
or2
( Represent thestdout
andstderr
), Willbuf
First addresslen
Bytes output to serial port ( Use_putc()
that will do ) - Set the correct return value , Otherwise, the caller of the system call will think
write
Failed to execute successfully , To retry - stay
navy-apps/libs/libos/src/nanos.c
Of_write()
Call the system call interface function
have access to fs_write
Function check fd
Value , Write the specified length bytes of the given buffer to the file with the specified file number ,fs_write
Prototype :
ssize_t fs_write(int fd, uint8_t *buf, size_t len){
Finfo *fp = &file_table[fd];
ssize_t delta_len = fp->size - fp->open_offset;
ssize_t write_len = delta_len < len?delta_len:len;
size_t i = 0;
switch(fd){
//case FD_STDIN: return -1;
case FD_STDOUT: case FD_STDERR:
while(i++ < len) _putc(*buf++);
return len;
case FD_FB:
fb_write(buf, fp->open_offset, len);
break;
default:
if(fd < 6 || fd >= NR_FILES) return -1;
ramdisk_write(buf, fp->disk_offset + fp->open_offset, write_len);
break;
}
fp->open_offset += write_len;
return write_len;
}
completion sys_write()
:
static inline uintptr_t sys_write(uintptr_t fd, uintptr_t buf, uintptr_t len) {
return fs_write(fd, (uint8_t *)buf, len);
}
stay navy-apps/libs/libos/src/nanos.c
modify _write()
:
int _write(int fd, void *buf, size_t count){
_syscall_(SYS_write, fd, (uintptr_t)buf, count);
}
completion do_syscall function :
_RegSet* do_syscall(_RegSet *r) {
uintptr_t a[4];
a[0] = SYSCALL_ARG1(r);
a[1] = SYSCALL_ARG2(r);
a[2] = SYSCALL_ARG3(r);
a[3] = SYSCALL_ARG4(r);
switch (a[0]) {
case SYS_none: r->eax = 1; break;
case SYS_exit: _halt(a[1]); break;
+ case SYS_write: r->eax = sys_write(a[1], a[2], a[3]); break;
default: panic("Unhandled syscall ID = %d", a[0]);
}
function :
clear && cd ~/ics2022/navy-apps/tests/hello/ && make && cd ~/ics2022/nanos-lite/ && make update && make run
After running, some instructions are not implemented :
Hello World!
invalid opcode(eip = 0x04000d2f): f6 46 0c 08 74 3f 8b 46 ...
There are two cases which will trigger this unexpected exception:
1. The instruction at eip = 0x04000d2f is not implemented.
2. Something is implemented incorrectly.
Find this eip(0x04000d2f) in the disassembling result to distinguish which case it is.
If it is the first case, see
_ ____ ___ __ __ __ _
(_)___ \ / _ \ / / | \/ | | |
_ __) | (_) |/ /_ | \ / | __ _ _ __ _ _ __ _| |
| ||__ < > _ <| '_ \ | |\/| |/ _` | '_ \| | | |/ _` | |
| |___) | (_) | (_) | | | | | (_| | | | | |_| | (_| | |
|_|____/ \___/ \___/ |_| |_|\__,_|_| |_|\__,_|\__,_|_|
for more details.
If it is the second case, remember:
* The machine is always right!
* Every line of untested code is always wrong!
stay ~/ics2022/nemu/src/cpu/exec/exec.c
add to test Instructions :
/* 0xf6, 0xf7 */
make_group(gp3,
IDEX(test_I, test), EMPTY, EX(not), EX(neg),
EX(mul), EX(imul1), EX(div), EX(idiv))
function :
clear && cd ~/ics2022/navy-apps/tests/hello/ && make && cd ~/ics2022/nanos-lite/ && make update && make run
Successful implementation :
(nemu) c
[src/main.c,19,main] 'Hello World!' from Nanos-lite
[src/main.c,20,main] Build time: 20:45:48, May 29 2022
[src/ramdisk.c,26,init_ramdisk] ramdisk info: start = 0x101ac0, end = 0x107dfc, size = 25404 bytes
[src/main.c,27,main] Initializing interrupt/exception handler...
Hello World!
Hello World for the 2th time
Hello World for the 3th time
Hello World for the 4th time
Hello World for the 5th time
Hello World for the 6th time
Hello World for the 7th time
Hello World for the 8th time
Hello World for the 9th time
Hello World for the 10th time
...
Realize heap management (10 branch )
- System commissioning related to reactor area management ⽤ And encapsulated functions , Such as sys_brk,mm_brk, _sbrk(), brk(), sbrk()
Handout tips : So we just need to let SYS_brk
System calls always return 0
that will do , Indicates that the heap size adjustment is always successful . So in nanos-lite/src/syscall.c
modify do_syscall
function :
_RegSet* do_syscall(_RegSet *r) {
uintptr_t a[4];
a[0] = SYSCALL_ARG1(r);
a[1] = SYSCALL_ARG2(r);
a[2] = SYSCALL_ARG3(r);
a[3] = SYSCALL_ARG4(r);
switch (a[0]) {
case SYS_none: r->eax = 1; break;
case SYS_exit: _halt(a[1]); break;
case SYS_write: r->eax = sys_write(a[1], a[2], a[3]); break;
+ case SYS_brk: r->eax = 0; break;
default: panic("Unhandled syscall ID = %d", a[0]);
}
stay navy-apps/libs/libos/src/nanos.c
Realization _sbrk()
.
extern char _end;
intptr_t program_break = (intptr_t)&_end; // Record the starting position
void *_sbrk(intptr_t increment){
intptr_t old_program_break = program_break;
if (_syscall_(SYS_brk, program_break + increment, 0, 0) == 0) {
// system call
program_break = program_break + increment; // Record the added position
return (void *)old_program_break; // If successful , Then return to the original position
}
else
return (void *)-1;
}
First pair nanos-lite/Makefile
Make the following changes :
-update: update-ramdisk-objcopy src/syscall.h
+update: update-ramdisk-fsimg src/syscall.h
Handout tips : Use the file read / write function to open the file that you want loader Read file , And read the content of the corresponding size to the specified memory address , Close the file after reading . modify nanos-lite/src/loader.c
Realization loader
, Pay attention to adding header files :
#include "fs.h"
uintptr_t loader(_Protect *as, const char *filename) {
int fd = fs_open(filename, 0, 0);
size_t f_size = fs_filesz(fd);
fs_read(fd, DEFAULT_ENTRY, f_size);
fs_close(fd);
return (uintptr_t)DEFAULT_ENTRY;
}
After changing the user program, you only need to modify the incoming loader()
Function file name , No need to update ramdisk The content of .
modify nanos-lite/src/main.c
in loader
The parameters of the function :
uint32_t entry = loader(NULL, "/bin/text");
Realize system debugging ⽤(10 branch )
- add to
SYS_open
、SYS_read
、SYS_lseek
、SYS_close
system call
_RegSet* do_syscall(_RegSet *r) {
uintptr_t a[4];
a[0] = SYSCALL_ARG1(r);
a[1] = SYSCALL_ARG2(r);
a[2] = SYSCALL_ARG3(r);
a[3] = SYSCALL_ARG4(r);
switch (a[0]) {
case SYS_none: r->eax = 1; break;
case SYS_exit: _halt(a[1]); break;
case SYS_write: r->eax = sys_write(a[1], a[2], a[3]); break;
case SYS_brk: r->eax = 0; break;
+ case SYS_read: r->eax = fs_read(a[1], (uint8_t *)a[2], a[3]); break;
+ case SYS_open: r->eax = fs_open((char *)a[1], a[2], a[3]); break;
+ case SYS_close: r->eax = fs_close(a[1]); break;
+ case SYS_lseek: r->eax = fs_lseek(a[1], a[2], a[3]); break;
default: panic("Unhandled syscall ID = %d", a[0]);
}
modify navy-apps/libs/libos/src/nanos.c
The corresponding interface function in :
int _open(const char *path, int flags, mode_t mode) {
return _syscall_(SYS_open, (uintptr_t)path, flags, mode);
}
int _write(int fd, void *buf, size_t count){
return _syscall_(SYS_write, fd, (uintptr_t)buf, count);
}
int _read(int fd, void *buf, size_t count) {
return _syscall_(SYS_read, fd, (uintptr_t)buf, count);
}
int _close(int fd) {
return _syscall_(SYS_close, fd, 0, 0);
}
off_t _lseek(int fd, off_t offset, int whence) {
return _syscall_(SYS_lseek, fd, offset, whence);
}
test /bin/text:
cd ~/ics2022/nanos-lite/ && make update && make run
Successful implementation :
Welcome to NEMU!
[src/monitor/monitor.c,30,welcome] Build time: 11:16:55, May 30 2022
For help, type "help"
(nemu) c
[src/main.c,19,main] 'Hello World!' from Nanos-lite
[src/main.c,20,main] Build time: 19:06:54, May 31 2022
[src/ramdisk.c,26,init_ramdisk] ramdisk info: start = 0x101de0, end = 0x4390246, size = 69788774 bytes
[src/main.c,27,main] Initializing interrupt/exception handler...
PASS!!!
nemu: HIT GOOD TRAP at eip = 0x001000f1
Successful transportation ⾏ Each test ⽤ example (20 branch )
- /bin/bmptest
modify nanos-lite/src/main.c
in loader
The parameters of the function :
uint32_t entry = loader(NULL, "/bin/bmptest");
test /bin/bmptest:
cd ~/ics2022/nanos-lite/ && make update && make run
Tips :
invalid opcode(eip = 0x0400274c): a4 39 d7 75 fb 5e 5f 5d ...
There are two cases which will trigger this unexpected exception:
1. The instruction at eip = 0x0400274c is not implemented.
2. Something is implemented incorrectly.
Find this eip(0x0400274c) in the disassembling result to distinguish which case it is.
If it is the first case, see
_ ____ ___ __ __ __ _
(_)___ \ / _ \ / / | \/ | | |
_ __) | (_) |/ /_ | \ / | __ _ _ __ _ _ __ _| |
| ||__ < > _ <| '_ \ | |\/| |/ _` | '_ \| | | |/ _` | |
| |___) | (_) | (_) | | | | | (_| | | | | |_| | (_| | |
|_|____/ \___/ \___/ |_| |_|\__,_|_| |_|\__,_|\__,_|_|
for more details.
If it is the second case, remember:
* The machine is always right!
* Every line of untested code is always wrong!
function /bin/bmptest
when , Encounter tips a4
This instruction is not implemented , stay navy-apps/Makefile.compile
modify o2
by o0
that will do , This turns off code optimization , Avoided ⼀ Some data is not saved . Then run the following command :
cd ~/ics2022 && make clean && cd ~/ics2022/nanos-lite/ && make update && make run
Must be in the project directory make clean
, Otherwise, it still appears a4
Instruction not implemented . The successful running :
- /bin/events
modify nanos-lite/src/main.c
in loader
The parameters of the function :
uint32_t entry = loader(NULL, "/bin/events");
test /bin/events:
cd ~/ics2022/nanos-lite/ && make update && make run
Press the keyboard in the window that appears , The successful running :
(nemu) c
[src/main.c,19,main] 'Hello World!' from Nanos-lite
[src/main.c,20,main] Build time: 19:37:54, May 31 2022
[src/ramdisk.c,26,init_ramdisk] ramdisk info: start = 0x101de0, end = 0x43a38ee, size = 69868302 bytes
[src/main.c,27,main] Initializing interrupt/exception handler...
receive event: t 760
receive event: t 2292
receive event: t 2930
receive event: kd W
receive event: ku W
receive event: kd D
receive event: ku D
receive event: kd S
receive event: ku S
receive event: kd F
receive event: ku F
- Fairy sword legend
modify nanos-lite/src/main.c
in loader
The parameters of the function :
uint32_t entry = loader(NULL, "/bin/pal");
download pal file , Can be in https://github.com/yym68686/ics2022.git download pal.tar.bz2
, Extract to the specified directory :
mkdir -p ~/ics2022/navy-apps/fsimg/share/games && tar -xjf pal.tar.bz2 -C ~/ics2022/navy-apps/fsimg/share/games
test /bin/pal:
cd ~/ics2022/nanos-lite/ && make update && make run
The successful running :
References
https://blog.csdn.net/qq_21110935/article/details/80292718
边栏推荐
- 施努卡:机器人视觉抓取工作原理 机器视觉抓取
- Common shortcut keys in IDA
- Is the gold content of intermediate e-commerce division in the soft exam high?
- 1321: [example 6.3] deletion problem (noip1994)
- I plan to take part in security work. How about information security engineers and how to prepare for the soft exam?
- P1223 queuing for water /1319: [example 6.1] queuing for water
- Trajectory planning for multi-robot systems: Methods and applications 综述阅读笔记
- 简单易修改的弹框组件
- 软考一般什么时候出成绩呢?在线蹬?
- BigDecimal数值比较
猜你喜欢
打算参加安全方面工作,信息安全工程师怎么样,软考考试需要怎么准备?
深入分析ERC-4907协议的主要内容,思考此协议对NFT市场流动性意义!
The variables or functions declared in the header file cannot be recognized after importing other people's projects and adding the header file
5个chrome简单实用的日常开发功能详解,赶快解锁让你提升更多效率!
使用 load_decathlon_datalist (MONAI)快速加载JSON数据
简单易修改的弹框组件
I plan to take part in security work. How about information security engineers and how to prepare for the soft exam?
openinstall与虎扑达成合作,挖掘体育文化产业数据价值
Prototype object in ES6
Five simple and practical daily development functions of chrome are explained in detail. Unlock quickly to improve your efficiency!
随机推荐
1321: [example 6.3] deletion problem (noip1994)
求方程ax^2+bx+c=0的根(C语言)
移动端通过设置rem使页面内容及字体大小自动调整
【推荐系统 02】DeepFM、YoutubeDNN、DSSM、MMOE
How to successfully pass the senior system architecture designer in the second half of the year?
2022.7.3DAY595
HDU-2196 树形DP学习笔记
CAS mechanism
ThreadLocal is not enough
ADB utility commands (network package, log, tuning related)
When there are pointer variable members in the custom type, the return value and parameters of the assignment operator overload must be reference types
[daiy5] jz77 print binary tree in zigzag order
I plan to take part in security work. How about information security engineers and how to prepare for the soft exam?
555电路详解
Find the greatest common divisor and the least common multiple (C language)
1321:【例6.3】删数问题(Noip1994)
对word2vec的一些浅层理解
【PyTorch 07】 动手学深度学习——chapter_preliminaries/ndarray 习题动手版
A small problem of bit field and symbol expansion
IIC Basics